Use Spring dependency injection on a custom Hibernate validator - java

I want to create my own Hibernate custom Validator and what I would like to do is to add custom logic based on some information gathered from a different context (a different Spring bean)
On my custom implementation, I have tried to both add a constructor and define the validator in a spring bean, or to use the Autowire annotation and none of them worked
Autowire example:
public class MyCustomValidator implements ConstraintValidator<CustomConstraint, String> {
#Autowired
private MyCustomChecker customChecker;
#Override
public void initialize(CustomConstraint constraintAnnotation) {
}
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (null == value) {
return true;
}
//get user authenticated properties to perform validation based on the user
AuthenticatedIdentity identity = Context.getAuthenticatedIdentity();
return customChecker.isWhitelisted(identity);
}
}
Constructor example:
public class MyCustomValidator implements ConstraintValidator<CustomConstraint, String> {
private MyCustomChecker customChecker;
public MetricDataSizeValidator(MyCustomChecker customChecker) {
this.customChecker = customChecker;
}
#Override
public void initialize(CustomConstraint constraintAnnotation) {
}
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (null == value) {
return true;
}
//get user authenticated properties to perform validation based on the user
AuthenticatedIdentity identity = Context.getAuthenticatedIdentity();
return customChecker.isWhitelisted(identity);
}
}
I've read around on the official Hibernate doc but that doesn't quite answer my question.
I am pretty sure this is a common issue when you want to validate based on some information based from a different context, however I didn't find around an answer for this.
My app is using Spring DI, where my bean is already initialized like this
<bean id="customChecker" class="com.mycomp.CustomChecker">
<constructor-arg>
<value>arg</value>
</constructor-arg>
</bean>
Is there any example around of how to achieve this?
Update
If I configure my Validator to be:
<bean id="validatorFactory" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean id="validator" factory-bean="validatorFactory"
factory-method="getValidator" />
Now I can see the validation is wired up correctly using spring beans. However, now I'm doubtful whether I'm using HibernateValidator (I think I'm not). Is there any way to achieve the same but configure HibernateValidator factory to use Spring beans?

I assume your MyCustomValidator is not recognized as a managed spring bean, so no autowiring will occur.
The easiest way to make your MyCustomValidator a spring bean is to add the #Component annotation at the class level.

You can use InitBinder in case of Spring MVC where your custom validator will automatically called by the RequestMappingHandlerAdapter.
Simply annotate your method in the controller with #InitBinder and inside the method provide your validator and provide the your validator class to WebDataBinder by calling webDataBinder.setValidator()

Related

Spring - Validation of custom constraints

I have a custom annotation #UniqueModel, which is validated by a ConstraintValidator:
#Component
public class UniquePlaceValidator implements ConstraintValidator<UniqueModel, Model> {
#Autowired
private ModelRepository repository;
public UniqueModelValidator() {
}
public void initialize(UniqueModel constraint) {
}
#Override
public boolean isValid(Model model, ConstraintValidatorContext context) {
if (repository == null)
return true;
Model dbModel = repository.findByNameAndMail(model.getName(), model.getMail());
return dbModel == null;
}
The problem is, that I need to do the validation before the safe()-method of the repository is called, otherwise the field injection won't work.
I therefor created a delegate-method with a #Valid-annotation, in order to force the unique-validation before:
Model save(#Valid Model model {
return repository.save(model);
}
Unfortunately this doesn't work, it seems like the #Valid-annotation is ignored by Spring.
How can I assure the correct timing of validation?
Depending on your Bean validation configuration you may need to annotate your repository bean with #ValidateOnExecution.
But I'm not sure if Spring does support this annoation (see SPR-10641) hence I'm using Spring's own #Validated annotation in my repository and service interfaces and method level validation works fine!
See also this question and have a look into MethodValidationPostProcessor which clearly states "Target classes with such annotated methods need to be annotated with Spring's #Validated annotation at the type level". So it seems to be pretty clear that you have to use #Validated instead of #ValidateOnExecution until SPR-10641 is fixed.

Spring bean injection - inject properties after bean has been defined

I have an application made up of 2 projects - UI and data. In the Data project, I have added a spring bean to the xml application context:
<bean id="mail-notification-service" class="com.test.DefaultEmailNotificationManager">
</bean>
This manager sends out notifications on request, and the parameters use a simple enum and a parameters object (both of which use classes only in the data project) to select an IEmailGenerator and use it to send the emails.
The manager is defined something like:
public class DefaultEmailNotificationManager implements IEmailNotificationManager {
public MailResult sendEmail( EmailType type ) { .. }
public void register( IEmailGenerator generator ) { .. }
}
public interface IEmailGenerator {
public EmailType getType();
}
Trouble is, the generators are defined in the UI project, so they can do things like get hold of wicket page classes, the request cycle, and application resources. Thus I can't add them to the bean in the data projects' applicationContext so that other modules in both the data and UI projects can use them.
Is there any way in the applicationContext of the UI project to do something like:
<bean id="exclusionNotifier" class="com.test.ui.ExclusionEmailNotifier"/>
<bean id="modificationNotifier" class="com.test.ui.ModificationEmailNotifier"/>
<call-method bean-ref="mail-notification-service" method="register">
<param name="generatorImplementation", ref="exclusionNotifier"/>
</call-method>
<call-method bean-ref="mail-notification-service" method="register">
<param name="generatorImplementation", ref="modificationNotifier"/>
</call-method>
I can manually tie the beans together in the WicketApplication.init method but would prefer something more elegant. Has anyone done anything like this?
Using Spring 4.1.4
Thanks in advance.
Inject generators into mail-notification-service bean (e.g. using autowire="byType") and register them right after bean construction using init-method (see Initialization callbacks in Spring docs)
public class DefaultEmailNotificationManager implements IEmailNotificationManager {
private Collection<IEmailGenerator> generators;
public void init() {
for( IEmailGenerator g : generators ) {
register(g);
}
}
public void setGenerators( Collection<IEmailGenerator> generators ) {
this.generators = generators;
}
public MailResult sendEmail( EmailType type ) { .. }
private void register( IEmailGenerator generator ) { .. }
}
data's applicationContext:
<bean id="mail-notification-service"
class="com.test.DefaultEmailNotificationManager"
init-method="init"
autowire="byType" />
UI's applicationContext:
<bean id="exclusionNotifier" class="com.test.ui.ExclusionEmailNotifier"/>
<bean id="modificationNotifier" class="com.test.ui.ModificationEmailNotifier"/>

DeltaSpike custom ConfigSource with CDI

I am trying to define a custom DeltaSpike ConfigSource. The custom config source will have the highest priority and check the database for the config parameter.
I have a ConfigParameter entity, that simply has a key and a value.
#Entity
#Cacheable
public class ConfigParameter ... {
private String key;
private String value;
}
I have a #Dependent DAO that finds all config parameters.
What I am trying to do now, is define a custom ConfigSource, that is able to get the config parameter from the database. Therefore, I want to inject my DAO in the ConfigSource. So basically something like
#ApplicationScoped
public class DatabaseConfigSource implements ConfigSource {
#Inject
private ConfigParameterDao configParameterDao;
....
}
However, when registering the ConfigSource via META-INF/services/org.apache.deltaspike.core.spi.config.ConfigSource, the class will be instantiated and CDI will not work.
Is there any way to get CDI working in this case?
Thanks in advance, if you need any further information, please let me know.
The main problem is, that the ConfigSource gets instantiated very early on when the BeanManager is not available yet. Even the JNDI lookup does not work at that point in time. Thus, I need to delay the injection/lookup.
What I did now, is add a static boolean to my config source, that I set manually. We have a InitializerService that makes sure that the system is setup properly. At the end of the initialization process, I call allowInitialization() in order to tell the config source, that the bean is injectable now. Next time the ConfigSource is asked, it will be able to inject the bean using BeanProvider.injectFields.
public class DatabaseConfigSource implements ConfigSource {
private static boolean allowInit;
#Inject
private ConfigParameterProvider configParameterProvider;
#Override
public int getOrdinal() {
return 500;
}
#Override
public String getPropertyValue(String key) {
initIfNecessary();
if (configParameterProvider == null) {
return null;
}
return configParameterProvider.getProperty(key);
}
public static void allowInitialization() {
allowInit = true;
}
private void initIfNecessary() {
if (allowInit) {
BeanProvider.injectFields(this);
}
}
}
I have a request-scoped bean that holds all my config variables for type-safe access.
#RequestScoped
public class Configuration {
#Inject
#ConfigProperty(name = "myProperty")
private String myProperty;
#Inject
#ConfigProperty(name = "myProperty2")
private String myProperty2;
....
}
When injecting the Configuration class in a different bean, each ConfigProperty will be resolved. Since my custom DatabaseConfigSource has the highest ordinal (500), it will be used for property resolution first. If the property is not found, it will delegate the resolution to the next ConfigSource.
For each ConfigProperty the getPropertyValue function from the DatabaseConfigSource is called. Since I do not want to retreive the parameters from the database for each config property, I moved the config property resolution to a request-scoped bean.
#RequestScoped
public class ConfigParameterProvider {
#Inject
private ConfigParameterDao configParameterDao;
private Map<String, String> configParameters = new HashMap<>();
#PostConstruct
public void init() {
List<ConfigParameter> configParams = configParameterDao.findAll();
configParameters = configParams.stream()
.collect(toMap(ConfigParameter::getId, ConfigParameter::getValue));
}
public String getProperty(String key) {
return configParameters.get(key);
}
}
I could sure change the request-scoped ConfigParameterProvider to ApplicationScoped. However, we have a multi-tenant setup and the parameters need to be resolved per request.
As you can see, this is a bit hacky, because we need to explicitly tell the ConfigSource, when it is allowed to be instantiated properly (inject the bean).
I would prefer a standarized solution from DeltaSpike for using CDI in a ConfigSource. If you have any idea on how to properly realise this, please let me know.
Even though this post has been answered already I'd like to suggest another possible solution for this problem.
I managed to load properties from my db service by creating an #Signleton #Startup EJB which extends the org.apache.deltaspike.core.impl.config.BaseConfigSource and injects my DAO as delegate which I then registered into the org.apache.deltaspike.core.api.config.ConfigResolver.
#Startup
#Singleton
public class DatabaseConfigSourceBean extends BaseConfigSource {
private static final Logger logger = LoggerFactory.getLogger(DatabaseConfigSourceBean.class);
private #Inject PropertyService delegateService;
#PostConstruct
public void onStartup() {
ConfigResolver.addConfigSources(Collections.singletonList(this));
logger.info("Registered the DatabaseConfigSourceBean in the ConfigSourceProvider ...");
}
#Override
public Map<String, String> getProperties() {
return delegateService.getProperties();
}
#Override
public String getPropertyValue(String key) {
return delegateService.getPropertyValue(key);
}
#Override
public String getConfigName() {
return DatabaseConfigSourceBean.class.getSimpleName();
}
#Override
public boolean isScannable() {
return true;
}
}
I know that creating an EJB for this purpose basically produces a way too big overhead, but I think it's a bit of a cleaner solution instead of handling this problem by some marker booleans with static accessors ...
DS is using the java se spi mechanism for this which is not CD'Injectable'. One solution would be to use the BeanProvider to get hold of your DatabaseConfigSource and delegate operations to it.

Java Spring #Valid on a method call [duplicate]

Hej,
I want to use the #Validated(group=Foo.class) annotation to validate an argument before executing a method like following:
public void doFoo(Foo #Validated(groups=Foo.class) foo){}
When i put this method in the Controller of my Spring application, the #Validated is executed and throws an error when the Foo object is not valid. However if I put the same thing in a method in the Service layer of my application, the validation is not executed and the method just runs even when the Foo object isn't valid.
Can't you use the #Validated annotation in the service layer ? Or do I have to do configure something extra to make it work ?
Update:
I have added the following two beans to my service.xml:
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>
and replaced the #Validate with #Null like so:
public void doFoo(Foo #Null(groups=Foo.class) foo){}
I know it is a pretty silly annotation to do but I wanted to check that if I call the method now and passing null it would throw an violation exception which it does. So why does it execute the #Null annotation and not the #Validate annotation ? I know one is from javax.validation and the other is from Spring but I do not think that has anything to do with it ?
In the eyes of a Spring MVC stack, there is no such thing as a service layer. The reason it works for #Controller class handler methods is that Spring uses a special HandlerMethodArgumentResolver called ModelAttributeMethodProcessor which performs validation before resolving the argument to use in your handler method.
The service layer, as we call it, is just a plain bean with no additional behavior added to it from the MVC (DispatcherServlet) stack. As such you cannot expect any validation from Spring. You need to roll your own, probably with AOP.
With MethodValidationPostProcessor, take a look at the javadoc
Applicable methods have JSR-303 constraint annotations on their
parameters and/or on their return value (in the latter case specified
at the method level, typically as inline annotation).
Validation groups can be specified through Spring's Validated
annotation at the type level of the containing target class, applying
to all public service methods of that class. By default, JSR-303 will
validate against its default group only.
The #Validated annotation is only used to specify a validation group, it doesn't itself force any validation. You need to use one of the javax.validation annotations like #Null or #Valid. Remember that you can use as many annotations as you would like on a method parameter.
As a side note on Spring Validation for methods:
Since Spring uses interceptors in its approach, the validation itself is only performed when you're talking to a Bean's method:
When talking to an instance of this bean through the Spring or JSR-303 Validator interfaces, you'll be talking to the default Validator of the underlying ValidatorFactory. This is very convenient in that you don't have to perform yet another call on the factory, assuming that you will almost always use the default Validator anyway.
This is important because if you're trying to implement a validation in such a way for method calls within the class, it won't work. E.g.:
#Autowired
WannaValidate service;
//...
service.callMeOutside(new Form);
#Service
public class WannaValidate {
/* Spring Validation will work fine when executed from outside, as above */
#Validated
public void callMeOutside(#Valid Form form) {
AnotherForm anotherForm = new AnotherForm(form);
callMeInside(anotherForm);
}
/* Spring Validation won't work for AnotherForm if executed from inner method */
#Validated
public void callMeInside(#Valid AnotherForm form) {
// stuff
}
}
Hope someone finds this helpful. Tested with Spring 4.3, so things might be different for other versions.
#pgiecek You don't need to create a new Annotation. You can use:
#Validated
public class MyClass {
#Validated({Group1.class})
public myMethod1(#Valid Foo foo) { ... }
#Validated({Group2.class})
public myMethod2(#Valid Foo foo) { ... }
...
}
Be careful with rubensa's approach.
This only works when you declare #Valid as the only annotation. When you combine it with other annotations like #NotNull everything except the #Valid will be ignored.
The following will not work and the #NotNull will be ignored:
#Validated
public class MyClass {
#Validated(Group1.class)
public void myMethod1(#NotNull #Valid Foo foo) { ... }
#Validated(Group2.class)
public void myMethod2(#NotNull #Valid Foo foo) { ... }
}
In combination with other annotations you need to declare the javax.validation.groups.Default Group as well, like this:
#Validated
public class MyClass {
#Validated({ Default.class, Group1.class })
public void myMethod1(#NotNull #Valid Foo foo) { ... }
#Validated({ Default.class, Group2.class })
public void myMethod2(#NotNull #Valid Foo foo) { ... }
}
As stated above to specify validation groups is possible only through #Validated annotation at class level. However, it is not very convenient since sometimes you have a class containing several methods with the same entity as a parameter but each of which requiring different subset of properties to validate. It was also my case and below you can find several steps to take to solve it.
1) Implement custom annotation that enables to specify validation groups at method level in addition to groups specified through #Validated at class level.
#Target({ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface ValidatedGroups {
Class<?>[] value() default {};
}
2) Extend MethodValidationInterceptor and override determineValidationGroups method as follows.
#Override
protected Class<?>[] determineValidationGroups(MethodInvocation invocation) {
final Class<?>[] classLevelGroups = super.determineValidationGroups(invocation);
final ValidatedGroups validatedGroups = AnnotationUtils.findAnnotation(
invocation.getMethod(), ValidatedGroups.class);
final Class<?>[] methodLevelGroups = validatedGroups != null ? validatedGroups.value() : new Class<?>[0];
if (methodLevelGroups.length == 0) {
return classLevelGroups;
}
final int newLength = classLevelGroups.length + methodLevelGroups.length;
final Class<?>[] mergedGroups = Arrays.copyOf(classLevelGroups, newLength);
System.arraycopy(methodLevelGroups, 0, mergedGroups, classLevelGroups.length, methodLevelGroups.length);
return mergedGroups;
}
3) Implement your own MethodValidationPostProcessor (just copy the Spring one) and in the method afterPropertiesSet use validation interceptor implemented in step 2.
#Override
public void afterPropertiesSet() throws Exception {
Pointcut pointcut = new AnnotationMatchingPointcut(Validated.class, true);
Advice advice = (this.validator != null ? new ValidatedGroupsAwareMethodValidationInterceptor(this.validator) :
new ValidatedGroupsAwareMethodValidationInterceptor());
this.advisor = new DefaultPointcutAdvisor(pointcut, advice);
}
4) Register your validation post processor instead of Spring one.
<bean class="my.package.ValidatedGroupsAwareMethodValidationPostProcessor"/>
That's it. Now you can use it as follows.
#Validated(groups = Group1.class)
public class MyClass {
#ValidatedGroups(Group2.class)
public myMethod1(Foo foo) { ... }
public myMethod2(Foo foo) { ... }
...
}

Discovering annotated methods

In my Spring application, I have components that use Spring's caching mechanism. Each #Cacheable annotation specifies the cache that is to be used. I'd like to autodiscover all the caches that are needed at startup so that they can be automatically configured.
The simplest approach seemed to create a marker interface (ex: CacheUser) to be used by each caching component:
#Component
public class ComponentA implements CacheUser {
#Cacheable("dictionaryCache")
public String getDefinition(String word) {
...
}
}
I would then have Spring autodiscover all the implementations of this interface and autowire them to a configuration list that can be used when configuring the cache manager(s). This works.
#Autowired
private Optional<List<CacheUser>> cacheUsers;
My plan was to take each discovered class and find all methods annotated with #Cacheable. From there I would access the annotation's properties and obtain the cache name. I'm using AnnotationUtils.findAnnotation() to get the annotation declaration.
That's where the plan falls apart. Spring actually wires proxies instead of the raw component, and the annotations aren't copied over to the proxies' methods. The only workaround I've found exploits the fact that the proxy implements Advised which provides access to the proxied class:
((Advised)proxy).getTargetSource().getTargetClass().getMethods()
From there I can get the original annotations, but this approach is clearly brittle.
So two questions, really:
Is there a better way to get to the annotations defined by the proxied class?
Can you suggest any other way to discover all uses of #Cacheable in my project? I'd love to do without a marker interface.
Thanks!
Spring has a lot of infrastructure interfaces which can help you tap into the lifecycle of the container and/or beans. For your purpose you want to use a BeanPostProcessor and the SmartInitializingSingleton.
The BeanPostProcessor will get a callback for all the beans constructed, you will only need to implement the the postProcessAfterInitialization method. You can in that method detect the annotations and fill a list of caches.
Then in the SmartInitializingSingletons afterSingletonsInstantiated method you use this list to bootstrap/init your caches.
Something like the following (it is untested but should give you an idea).
public class CacheInitialingProcessor implements BeanPostProcessor, SmartInitializingSingleton {
private final Set<String> caches = new HashSet<String>();
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class<?> targetClass = AopUtils.getTargetClass(bean);
ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
#Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Cacheable cacheable = AnnotationUtils.getAnnotation(method, Cacheable.class);
if (cacheable != null) {
caches.addAll(Arrays.asList(cacheable.cacheNames()));
}
}
});
return bean;
}
#Override
public void afterSingletonsInstantiated() {
for (String cache : caches) {
// inti caches.
}
}
}

Categories