[ 
https://issues.apache.org/jira/browse/OPENEJB-1525?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13025356#comment-13025356
 ] 

Romain Manni-Bucau commented on OPENEJB-1525:
---------------------------------------------

To allow usage of hibernate-validator for this purpose the interceptor has to 
be modified like this:

{code}
package org.apache.openejb.bval;


import org.apache.bval.jsr303.extensions.MethodValidator;
import org.apache.openejb.core.ivm.naming.NamingException;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;

import javax.annotation.Resource;
import javax.ejb.EJBException;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import javax.naming.InitialContext;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import javax.validation.Validator;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Set;

/**
 * A simple interceptor to validate parameters and returned value using
 * bean validation spec. It doesn't use group for now.
 *
 * It is dependent of the Apache Bean Validation implementation.
 *
 * @author Romain Manni-Bucau
 */
public class BeanValidationAppendixInterceptor {
    private static final Logger logger = 
Logger.getInstance(LogCategory.OPENEJB, 
BeanValidationAppendixInterceptor.class);
    private static final Class<?> APACHE_BVAL_METHOD_CLASS = initApache();
    private static final Class<?> HIBERNATE_METHOD_CLASS = initHibernate();

    @AroundInvoke public Object aroundInvoke(final InvocationContext 
ejbContext) throws Exception {
        Object validatorObject = null;
        Validator validator = null;
        try {
            validator = (Validator) new 
InitialContext().lookup("java:comp/Validator");
        } catch (NamingException ne) {
            // no-op
        }

        Set<?> violations = Collections.emptySet();
        if (APACHE_BVAL_METHOD_CLASS != null && validator != null) {
            validatorObject = validator.unwrap(APACHE_BVAL_METHOD_CLASS);
            violations = call(Set.class, validatorObject, "validateParameters",
                new Object[]{
                    ejbContext.getTarget().getClass(), ejbContext.getMethod(), 
ejbContext.getParameters(), new Class[0]
                },
                new Class<?>[]{
                    Class.class, Method.class, Object[].class, Class[].class
                });
        } else if (HIBERNATE_METHOD_CLASS != null && validator != null) {
            validatorObject = validator.unwrap(HIBERNATE_METHOD_CLASS);
            violations = call(Set.class, validatorObject, 
"validateAllParameters",
                new Object[]{
                    ejbContext.getTarget(), ejbContext.getMethod(), 
ejbContext.getParameters(), new Class[0]
                },
                new Class<?>[]{
                    Object.class, Method.class, Object[].class, Class[].class
                });
        } else { // a warning message to inform Apache Bean Validation is not 
present
            if (validator == null) {
                logger.error("can't find validator");
            } else {
                logger.warning("Apache Bean Validation is not present, "
                    + BeanValidationAppendixInterceptor.class.getName() + " 
will not work. "
                    + "Please put it if you want to validate your parameters 
and returned values "
                    + "with bean validation JSR.");
            }
        }

        if (violations.size() > 0) {
            throw buildValidationException((Set<ConstraintViolation<?>>) 
violations);
        }

        Object returnedValue = ejbContext.proceed();

        violations = Collections.emptySet();
        if (validatorObject != null && APACHE_BVAL_METHOD_CLASS != null) {
            violations = call(Set.class, validatorObject, 
"validateReturnedValue",
                new Object[]{
                    ejbContext.getTarget().getClass(), ejbContext.getMethod(), 
returnedValue, new Class[0]
                },
                new Class<?>[]{
                    Class.class, Method.class, Object.class, Class[].class
                });
        } else if (validatorObject != null && HIBERNATE_METHOD_CLASS != null) {
            violations = call(Set.class, validatorObject, "validateReturnValue",
                new Object[]{
                    ejbContext.getTarget(), ejbContext.getMethod(), 
returnedValue, new Class[0]
                },
                new Class<?>[]{
                    Object.class, Method.class, Object.class, Class[].class
                });
        }

        if (violations.size() > 0) {
            throw buildValidationException((Set<ConstraintViolation<?>>) 
violations);
        }

        return returnedValue;
    }

    // just a simple EJBException for now
    private RuntimeException 
buildValidationException(Set<ConstraintViolation<?>> violations) {
        return new ConstraintViolationException(violations);
    }

    private static <T> T call(Class<T> returnedType, Object o, String 
methodName, Object[] params, Class<?>[] types) {
        Method method = null;
        boolean accessible = true;
        try {
            method = o.getClass().getMethod(methodName, types);
            accessible = method.isAccessible();
            if (!accessible) {
                accessible = false;
                method.setAccessible(true);
            }
            return (T) method.invoke(o, params);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ValidationException("can't call method " + methodName + " 
on " + o, e);
        } finally {
            if (method != null) {
                method.setAccessible(accessible);
            }
        }
    }

    private static ClassLoader getClassLaoder() {
        ClassLoader classLoader = 
Thread.currentThread().getContextClassLoader();
        if (classLoader == null) {
            classLoader = 
BeanValidationAppendixInterceptor.class.getClassLoader();
        }
        return classLoader;
    }

    private static Class<?> initApache() {
        try {
            return 
getClassLaoder().loadClass("org.apache.bval.jsr303.extensions.MethodValidator");
        } catch (ClassNotFoundException e) {
            return null;
        }
    }

    private static Class<?> initHibernate() {
        ClassLoader classLoader = 
Thread.currentThread().getContextClassLoader();
        if (classLoader == null) {
            classLoader = 
BeanValidationAppendixInterceptor.class.getClassLoader();
        }
        try {
            return 
getClassLaoder().loadClass("org.hibernate.validator.method.MethodValidator");
        } catch (ClassNotFoundException e) {
            return null;
        }
    }
}
{code}

Note: hibernate validator only allows constraints on root interface whereas 
apache bean validation needs it on child class.


> bean validation for parameters and returned values
> --------------------------------------------------
>
>                 Key: OPENEJB-1525
>                 URL: https://issues.apache.org/jira/browse/OPENEJB-1525
>             Project: OpenEJB
>          Issue Type: New Feature
>          Components: general
>    Affects Versions: (trunk/openejb3)
>            Reporter: Romain Manni-Bucau
>            Priority: Minor
>         Attachments: bean_validation_appendix_4.0.0_r1094584.patch
>
>
> Apache bean validation implemented the appendix of the bean validation spec 
> allowing to validate with bean validation annotations method parameters and 
> method returned values.
> It could be pretty cool to add an interceptor to activate it.
> It should be possible as a "general interceptor" (system interceptor 
> probably).

--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira

Reply via email to