Announcement Announcement Module
Collapse
No announcement yet.
Annotation driven JSR-303 validation on service and dao tier Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Annotation driven JSR-303 validation on service and dao tier

    Hi all,
    I'm building our own DAO tier based on a Datanucleus plugin I've written and Cassandra. I want to use the Hibernate implementation of the validator to validate objects before they're persisted in the data access tier. However, my objects are never validated before they're persisted. I have the following basic User model.

    Code:
    @PersistenceCapable
    public class User {
    
    	@PrimaryKey
    	@Persistent
    	@NotNull
    	@Email
    	private String email;
    
    	@Persistent
    	@NotNull
    	private String password;
    
    	@Persistent
    	@NotNull
    	private String firstName;
    
    	@Persistent
    	@NotNull
    	private String lastName;
    
    //getters and setters..
    }
    In my DAO, I have this implementation

    Code:
    @Override
    	public void save(@Valid T model) {
    		this.getJdoTemplate().makePersistent(model);
    		
    	}
    However, my model is never validated. Here is what I have in my context configuration.

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    	xmlns:tx="http://www.springframework.org/schema/tx"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
    	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    
    	<!--  Tell spring to scan our classes for annotations -->
    
    	<context:component-scan base-package="com.spidertracks.dataaccess" />
    
    	<bean id="pmf"
    		class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean">
    		<property name="jdoProperties">
    			<props>
    				<prop key="javax.jdo.PersistenceManagerFactoryClass">org.datanucleus.jdo.JDOPersistenceManagerFactory
    				</prop>
    				<prop key="javax.jdo.option.ConnectionURL">${cassandra.url}</prop>
    			</props>
    		</property>
    	</bean>
    
    	<!-- Transaction Manager for PMF -->
    	<bean id="transactionManager" class="org.springframework.orm.jdo.JdoTransactionManager">
    		<property name="persistenceManagerFactory">
    			<ref local="pmf" />
    		</property>
    	</bean>
    
    	<!--  tell our transaction interceptors to look at our annotations -->
    	<tx:annotation-driven transaction-manager="transactionManager" />
    	
    	<!--  set up our JSR 303 validator to use annotations -->
    	<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
    
    	<!--
    		references a properties file on the classpath. Set up internally for
    		unit testing, but overridden by each node individually
    	-->
    	<bean id="config"
    		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    		<property name="location"
    			value="classpath:/com/spidertracks/dataaccess/config.properties"></property>
    	</bean>
    
    <aop:config proxy-target-class="true">
    		<aop:pointcut id="validatableMethodExecution"
    			expression="execution(* com.spidertracks.dataaccess..*.*(..)) and @annotation(javax.validation.Valid)" />
    
    		<aop:aspect id="validateArgumentsAndReturnObject" ref="validatorAspect">
    			<aop:around pointcut-ref="validatableMethodExecution" method="validate" />
    		</aop:aspect>
    	</aop:config>
    
    	<!----> <bean id="validatorAspect" class="com.spidertracks.aviator.dataaccess.ModelValidatorAspect" ></bean>
     
    
    </beans>
    Here is my pointcut

    Code:
    
    public class ModelValidatorAspect {
    	@Autowired
    	private Validator validator;
    
        public Object validate(ProceedingJoinPoint pjp) throws Throwable {
        	
        	System.out.println("DOING INTERCEPTION!");
        	System.exit(0);
        	
            Set<ConstraintViolation> violations =new HashSet<ConstraintViolation>();
            
            for(Object obj : pjp.getArgs()) {
                if(obj != null) {
                    violations.addAll(validator.validate(obj));
                }
            }
            
            if(!violations.isEmpty()) {
               throw new ValidationException();
            }
    
            Object ret = pjp.proceed();
    
            return ret;
       }
    As you can see I've marked my User argument to my save method to be validated. However it isn't validated. What other setup do I need to do to get my validation working? Note that I'm using validation on my Service and DAO tiers, not on the web tier with MVC.

    Also, we'll be using Wicket for our web tier. A plugin already exists.

    http://blog.zenika.com/index.php?pos...303-Validators

    Is it possible for my business to tier to add extra validation errors? For instance, when the user changes their password, if the current password supplied is incorrect, the input fails validation in the change password use case.

    In regards to getting things working on the business tier, I've tried the code from this blog, but it doesn't seem to work.

    http://blog.newsplore.com/2010/02/23...-rest-rebuttal

    When I apply my own aop interception, it's never invoked. It's like it's not picking up on my validation of my method arguments.

    Thanks,
    Todd

    Thanks,
    Todd
    Last edited by tnine; May 31st, 2010, 05:05 AM. Reason: updated to appropriate title

  • #2
    Anyone? I'm a bit stuck, help would be greatly appreciated.

    Comment


    • #3
      Is your ModelValidatorAspect actually getting invoked? I'm guessing not, since you have a System.exit() in your example code.

      Your pointcut expression doesn't look quite right to me:

      Code:
      execution(* com.spidertracks.dataaccess..*.*(..)) and @annotation(javax.validation.Valid)
      I think this will intercept any method in the specified package where the @Valid annotation is applied to the method. In your case, you don't have the @Valid annotation on the method itself, but on one of the arguments to the method. Try moving the annotation to the method and see if that makes the pointcut work the way you are expecting.

      Comment

      Working...
      X