java - Getting Spring 4 dependency injection working with RESTeasy 3 validator -
i have been running lot of trouble trying custom bean validation constraints leverage spring's dependency injection.
for example might define constraint:
@constraint(validatedby = { customconstraintvalidator.class }) @documented @target({ elementtype.method, elementtype.field, elementtype.constructor, elementtype.parameter }) @retention(retentionpolicy.runtime) public @interface customconstraint { string message() default "custom.constraint.error"; class<?>[] groups() default {}; class<? extends payload>[] payload() default {}; }
validator implementation
@component public class customconstraint implements constraintvalidator<customconstraint, string> { @autowired private somespringbean somespringbean; @override public void initialize(customconstraint constraintannotation) { } @override public boolean isvalid(string value, constraintvalidatorcontext context) { if (value != null) { someobject storedvalue = somespringbean.find(value); return storedvalue != null; } return true; } }
the standard way setup bean validation resteasy pull in: org.jboss.resteasy:resteasy-validator-provider-11:3.0.6.final
however when validation executed @ runtime, @autowired field null.
versions
spring: 4.0.4.release
resteasy: 3.0.6.final
i have found solution, not ideal yet work , evolve proper solution.
after reading through many stackoverflow questions , various web articles found hardly references getting spring , resteasy working validation. there plenty of references spring , bean validation, once resteasy introduced discussion disappears. clear other discussions spring provides validatorfactory implementation called localvalidatorfactorybean enabled spring dependency injection within validator implementations.
looking org.jboss.resteasy:resteasy-validator-provider-11:3.0.6.final found out setting @provider instance provides generalvalidator used resteasy resolve bean validation. problem noticed provider class, validatorcontextresolver, not provide way set different version of validatorfactory. tries load via cdi / jndi , if fails defaults hardcoded validatorfactory implementation. in instance can't rely on jndi lookup there no way provide spring's localvalidatorfactorybean factory.
on other hand resteasy-validator-provider-11 small library , code need change instead use spring's localvalidatorfactorybean minimal. can drop resteasy-validator-provider-11 dependency , reimplement library use spring instead. show related code below working, leaving out classes resteasy-validator-provider-11 library did not change.
validatorcontextresolver
you need copy of localvalidatorfactorybean bootstrapped spring, cannot instantiate new
here:
@component @provider public class validatorcontextresolver implements contextresolver<generalvalidator> { private final static logger log = logger.getlogger(validatorcontextresolver.class); private volatile validatorfactory validatorfactory; final static object rd_lock = new object(); @autowired private validatorfactory springvalidatorfactorybean; // used initialized in static block, having trouble class loading context resolver in // environments. instead of failing , logging warning when resolver instantiated @ deploy time // log validation warning when trying obtain validatorfactory. validatorfactory getvalidatorfactory() { validatorfactory tmpvalidatorfactory = validatorfactory; if (tmpvalidatorfactory == null) { synchronized (rd_lock) { tmpvalidatorfactory = validatorfactory; if (tmpvalidatorfactory == null) { log.info("obtaining spring-bean enabled validator factory"); validatorfactory = tmpvalidatorfactory = springvalidatorfactorybean; } } } return validatorfactory; } @override public generalvalidator getcontext(class<?> type) { try { configuration<?> config = validation.bydefaultprovider().configure(); bootstrapconfiguration bootstrapconfiguration = config.getbootstrapconfiguration(); boolean isexecutablevalidationenabled = bootstrapconfiguration.isexecutablevalidationenabled(); set<executabletype> defaultvalidatedexecutabletypes = bootstrapconfiguration.getdefaultvalidatedexecutabletypes(); return new generalvalidatorimpl(getvalidatorfactory(), isexecutablevalidationenabled, defaultvalidatedexecutabletypes); } catch (exception e) { throw new validationexception("unable load validation support", e); } } }
springvalidationconfig
setup localvalidatorfactorybean bean in spring. can want, prefer programmatically
@configuration public class databaseconfig { @bean public validatorfactory validator() { localvalidatorfactorybean localvalidatorfactorybean = new localvalidatorfactorybean(); // localvalidatorfactorybean.setvalidationmessagesource(getvalidationmessagesource()); return localvalidatorfactorybean; } }
and configure spring load both of classes. component-scan in spring config like:
<context:component-scan base-package="org.example.resteasy.spring.validation.config" />
following these steps able @autowired dependency injection working in custom validation constraint implementations in question.
the ideal path forward have alternate resteasy-validator-provider-11 works spring.
Comments
Post a Comment