Package org.apache.onami.validation

Source Code of org.apache.onami.validation.ValidateMethodInterceptor

package org.apache.onami.validation;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import static java.lang.String.format;
import static java.util.Arrays.deepToString;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import javax.inject.Inject;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.bval.jsr303.extensions.MethodValidator;

/**
* Method interceptor for {@link Validate} annotation.
*/
final class ValidateMethodInterceptor
    implements MethodInterceptor
{

    private static final Class<?>[] CAUSE_TYPES = new Class[] { Throwable.class };

    private static final Class<?>[] MESSAGE_CAUSE_TYPES = new Class[] { String.class, Throwable.class };

    /**
     * The {@link ValidatorFactory} reference.
     */
    @Inject
    private ValidatorFactory validatorFactory;

    /**
     * {@inheritDoc}
     */
    public Object invoke( MethodInvocation invocation )
        throws Throwable
    {
        Validate validate = invocation.getMethod().getAnnotation( Validate.class );

        Validator validator = validatorFactory.getValidator();
        MethodValidator methodValidator = validator.unwrap( MethodValidator.class );

        Set<ConstraintViolation<?>> constraintViolations = new HashSet<ConstraintViolation<?>>();
        Class<?> clazz = invocation.getMethod().getDeclaringClass();
        Method method = invocation.getMethod();
        Object[] arguments = invocation.getArguments();
        Class<?>[] groups = validate.groups();

        constraintViolations.addAll( methodValidator.validateParameters( clazz, method, arguments, groups ) );

        if ( !constraintViolations.isEmpty() )
        {
            throw getException( new ConstraintViolationException( format( "Validation error when calling method '%s' with arguments %s",
                                                                          method,
                                                                          deepToString( arguments ) ),
                                                                  constraintViolations ),
                                validate.rethrowExceptionsAs(),
                                validate.exceptionMessage(),
                                arguments );
        }

        Object returnedValue = invocation.proceed();

        if ( validate.validateReturnedValue() )
        {
            constraintViolations.addAll( methodValidator.validateReturnedValue( clazz, method, returnedValue, groups ) );

            if ( !constraintViolations.isEmpty() )
            {
                throw getException( new ConstraintViolationException( format( "Method '%s' returned a not valid value %s",
                                                                              method,
                                                                              returnedValue ),
                                                                      constraintViolations ),
                                    validate.rethrowExceptionsAs(),
                                    validate.exceptionMessage(),
                                    arguments );
            }
        }

        return returnedValue;
    }

    /**
     * Define the {@link Throwable} has to be thrown when a validation error occurs and the user defined the custom
     * error wrapper.
     *
     * @param exception the occurred validation error.
     * @param exceptionWrapperClass the user defined custom error wrapper.
     * @return the {@link Throwable} has o be thrown.
     */
    private static Throwable getException( ConstraintViolationException exception,
                                           Class<? extends Throwable> exceptionWrapperClass,
                                           String exceptionMessage,
                                           Object[] arguments )
    {
        // check the thrown exception is of same re-throw type
        if ( exceptionWrapperClass == ConstraintViolationException.class )
        {
            return exception;
        }

        // re-throw the exception as new exception
        Throwable rethrowEx = null;

        String errorMessage;
        Object[] initargs;
        Class<?>[] initargsType;

        if ( exceptionMessage.length() != 0 )
        {
            errorMessage = format( exceptionMessage, arguments );
            initargs = new Object[] { errorMessage, exception };
            initargsType = MESSAGE_CAUSE_TYPES;
        }
        else
        {
            initargs = new Object[] { exception };
            initargsType = CAUSE_TYPES;
        }

        Constructor<? extends Throwable> exceptionConstructor = getMatchingConstructor( exceptionWrapperClass,
                                                                                        initargsType );
        if ( exceptionConstructor != null )
        {
            try
            {
                rethrowEx = exceptionConstructor.newInstance( initargs );
            }
            catch ( Exception e )
            {
                errorMessage = format( "Impossible to re-throw '%s', it needs the constructor with %s argument(s).",
                                       exceptionWrapperClass.getName(),
                                       Arrays.toString( initargsType ) );
                rethrowEx = new RuntimeException( errorMessage, e );
            }
        }
        else
        {
            errorMessage = format( "Impossible to re-throw '%s', it needs the constructor with %s or %s argument(s).",
                                   exceptionWrapperClass.getName(), Arrays.toString( CAUSE_TYPES ),
                                   Arrays.toString( MESSAGE_CAUSE_TYPES ) );
            rethrowEx = new RuntimeException( errorMessage );
        }

        return rethrowEx;
    }

    @SuppressWarnings( "unchecked" )
    private static <E extends Throwable> Constructor<E> getMatchingConstructor( Class<E> type, Class<?>[] argumentsType )
    {
        Class<? super E> currentType = type;
        while ( Object.class != currentType )
        {
            for ( Constructor<?> constructor : currentType.getConstructors() )
            {
                if ( Arrays.equals( argumentsType, constructor.getParameterTypes() ) )
                {
                    return (Constructor<E>) constructor;
                }
            }
            currentType = currentType.getSuperclass();
        }
        return null;
    }

}
TOP

Related Classes of org.apache.onami.validation.ValidateMethodInterceptor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.