I have an issue with bean autowiring inside a custom constraint validator. A constraint validator instance is not given using Spring's LocalValidatorFactoryBean. The JSR-303 provider is hibernate-validator 4.2.0.Final.
Spring configuration excerpt :
<!-- JSR 303 validation -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>
Custom Constraint Validator:
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.springframework.beans.factory.annotation.Autowired;
import com.model.Subject;
import com.services.SomeTypeService;
public class ReadOnlyValidator implements ConstraintValidator<ReadOnly, String> {
@Autowired
private SomeTypeService someTypeService;
@Override
public void initialize(ReadOnly constraintAnnotation) { }
@Override
public boolean isValid(String type, ConstraintValidatorContext context) {
try {
if (null != type) {
return !someTypeService.isReadonly(type);
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
Annotation:
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
@Target( { METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER } )
@Retention(RUNTIME)
@Constraint(validatedBy = ReadOnlyValidator.class)
@Documented
public @interface ReadOnly {
String message() default "{constraints.subjecttype.readonly}";
public abstract Class<?>[] groups() default {};
public abstract Class<? extends Payload>[] payload() default {};
}
SomeService:
@Validated
public interface SomeService {
...
public void updateType(@ReadOnly String type) throws SomeException;
...
}
SomeServiceImpl :
@Service
public class SomeServiceImpl implements SomeService {
...
public void updateType(String type) throws SomeException {
// do something
}
...
}
SomeTypeService is another @Service annotated bean that does not depend on SomeService ...
The problem is that I get an NPE as autowiring does not work; someone else is managing the custom validator instances and not Spring ...
Thanks in advance for any type of advice.
Found the problem. The same "validator" bean reference must be used by MethodValidationPostProcessor and mvc:annotation-driven declaration:
service-context.xml
<!-- JSR 303 validation -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">
<property name="validator" ref="validator"/>
</bean>
...
dispatcher-servlet.xml
...
<mvc:annotation-driven validator="validator" />
...
Tito, please check if you can use something like below for Java config:
@Configuration
public class SampleConfig {
...
@Bean
public Validator validator() {
return new LocalValidatorFactoryBean().getValidator();
}
@Bean
public MethodValidationPostProcessor mvpp() {
MethodValidationPostProcessor mvpp = new MethodValidationPostProcessor();
mvpp.setValidator(validator());
return mvpp;
}
...
}
To reuse the validator bean in a different configuration bean, you can use the @Import annotation.
来源:https://stackoverflow.com/questions/12676299/spring-3-1-autowiring-does-not-work-inside-custom-constraint-validator