Dependency Injection in JSR-303 ConstraintValidator - spring

I have the same problem that the guy from this thread has.
More precisely I get the following error, when trying to inject a bean in my custom validator that implements CustomValidator interface (it's a NPE when accessing the bean i wanted to inject):
javax.validation.ValidationException: HV000028: Unexpected exception during isValid call.
at org.hibernate.validator.internal.engine.ConstraintTree.validateSingleConstraint(ConstraintTree.java:294)
at org.hibernate.validator.internal.engine.ConstraintTree.validateConstraints(ConstraintTree.java:164)
at org.hibernate.validator.internal.engine.ConstraintTree.validateConstraints(ConstraintTree.java:125)
at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:86)
...
Caused by: java.lang.NullPointerException
Do you have a solution for this? Maybe an example? Because I tried the solutions offered on the other thread and nothing worked.
Any help is appreciated. Thanks.

You should not create validator factory on your own (Validation.buildDefaultValidatorFactory()) if you want to use Spring based constraint validators.
You should let Spring autowire correct factory to your bean:
#Controller
public class MyController {
#Autowired
private ValidatorFactory validatorFactory;
// ... handler methods
}

Related

#ConditionalOnBean not work for spring boot test

Hy everyone! I'm trying to solve the problem for a very long time.
There is very simple spring boot test
public class ApplicationTest {
#Test
void testContext() {
SpringApplication.run(Application.class);
}
}
And several beans...
#Service
#ConditionalOnBean(CommonService.class)
#RequiredArgsConstructor
public class SimpleHelper {
...
#Service
#RequiredArgsConstructor
#ConditionalOnBean(CommonFeignClient.class)
public class CommonService {
...
#FeignClient(
name = "CommonClient",
url = "localhost:8080"
)
public interface CommonFeignClient {
And the main class look as
#SpringBootApplication
#EnableFeignClients(clients = AnotherFeignClient.class)
public class Application {
When the spring application starts everything works ok. SimpleHelper does not created.
But in the spring boot test throw the exception:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'simpleHelper' defined in URL [...]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'foo.bar.CommonService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Please help, I don't understand what's going on anymore =)
Spring boot version is 2.3.0.RELEASE.
To use #ConditionalOnBean correctly, CommonService needs to be an auto-configuration class or defined as a bean by an auto-configured class rather than a service that's found by component scanning. This ensures that the bean on which CommonService is conditional has been defined before the condition is evaluated. The need for this is described in the annotation's javadoc:
The condition can only match the bean definitions that have been processed by the application context so far and, as such, it is strongly recommended to use this condition on auto-configuration classes only. If a candidate bean may be created by another auto-configuration, make sure that the one using this condition runs after.

BeanCurrentlyInCreationException when spring starts

I am getting the BeanCurrentlyInCreationException when I start my spring application.
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.datayes.bdb.rrp.business.service.impl.StockModelBaseService com.datayes.bdb.rrp.business.service.impl.StockModelV3ServiceImpl.stockModelBaseService; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'stockModelBaseService': Bean with name 'stockModelBaseService' has been injected into other beans [researchFrameworkCommonServiceImpl] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:561)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 71 more
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'stockModelBaseService': Bean with name 'stockModelBaseService' has been injected into other beans [researchFrameworkCommonServiceImpl] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:568)
And here are the code snippets I have found caused this issue:
#Component public class KafkaConsumerServer implements MessageListener<String, String> {
#Autowired StockModelV3Service stockModelV3Service;
#Autowired FinanceIndicatorService financeIndicatorService;
......
}
#Service public class FinanceIndicatorServiceImpl implements FinanceIndicatorService {
#Autowired StockModelV3Service stockModelV3Service;
#Autowired IndustryResearchFrameworkService industryResearchFrameworkService;
......
}
#Service public class IndustryResearchFrameworkServiceImpl implements IndustryResearchFrameworkService {
#Autowired ResearchFrameworkCommonService commonService;
......
}
#Service public class ResearchFrameworkCommonServiceImpl implements ResearchFrameworkCommonService {
#Autowired StockModelBaseService stockModelBaseService;
......
}
I found some thing interesting in the following article may have explained why.
https://blog.imaginea.com/spring-bean-creation-is-not-thread-safe/
As both my StockModelV3Service and FinanceIndicatorService depends on stockModelBaseService(FinanceIndicatorService -> industryResearchFrameworkService -> researchFrameworkCommonService -> stockModelBaseService), during spring bean creation, they have raced against each other. Which caused BeanCurrentlyInCreationException. As the above article noted, spring bean creation is not thread safe.
To solve this problem seems easy. I changed autowire order as below:
public class KafkaConsumerServer implements MessageListener<String, String> {
#Autowired FinanceIndicatorService financeIndicatorService;
#Autowired StockModelV3Service stockModelV3Service;
As FinanceIndicatorService also depends on StockModelV3Service, so when financeIndicatorService is loaded, it will wait till stockModelV3Service is loaded then load itself. Thus avoid BeanCurrentlyInCreationException.
After all, it has nothing to do with circular reference. As StockModelBaseService doesn't depends on other services.

ApplicationContext with same bean having #RequestMapping fails

In my applicationContext.xml I have 2 beans with same class and different id(test and test1). The application context gets loaded correctly, but when I add #RequestMapping to one method then the bean creation fails with the below error. This used to work with AnnotationMethodHandlerAdapter but its failing with RequestMappingHandlerMapping and RequestMappingHandlerAdapter.
Error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'test1' bean method
public java.lang.String com.test.render()
to {[/render],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}: There is already 'test' bean method
Please suggest how to fix this.
Code:
applicationContext.xml
<bean id="test" class="com.abc.test" />
<bean id="test1" class="com.abc.test" />
Controller
#Controller
#RequestMapping( value ={"/test/", "/test1/"})
public class test {
#RequestMapping("render")
public String render ()
{
//some code here.
}
}
You can do it like this...
switch from singleton approach to prototype and inside the xml do
While programmatically define
class P1 {
#Autowire
NotSoSingleton prototypedBean;
}
class P2 {
#Autowire
NotSoSingleton prototypedBean;
}
class P3 {
#Autowire
NotSoSingleton prototypedBean;
}
Would this approach do?
I could find a work around with this. This solution if for the comments I posted on 21-May
I used order property to instantiate the custom defined RequestMappingHandlerMapping in the xml file and it worked!!
It took my custom defined RequestMappingHandlerMapping instead of the default one loaded by <annotation-driven>.

Play Framework with Spring, #Transactional not working

I'm using Play Framework (2.2.2) in combination with Spring (using this template: https://github.com/jamesward/play-java-spring).
If I annotate the Application Controller with #Transactional it's working fine:
#org.springframework.stereotype.Controller
#Transactional
public class Application {
// ...
}
However, if I also extend from Play's Base Controller I get the following error:
[NoSuchBeanDefinitionException: No qualifying bean of type [controllers.Application] is defined]
Code:
#org.springframework.stereotype.Controller
#Transactional
public class Application extends play.mvc.Controller{
// ...
}
So for some reason the #TransactionalAnnotation combined with extends play.mvc.Controller leads to a NoSuchBeanDefinitionException.
Using either #Transactional OR extends play.mvc.Controller (not both combined) and Spring can instantiate the controller bean just fine.
How can I make them both work together?
This is the full stackstrace:
play.api.Application$$anon$1: Execution exception[[NoSuchBeanDefinitionException: No qualifying bean of type [controllers.Application] is defined]]
at play.api.Application$class.handleError(Application.scala:293) ~[play_2.10.jar:2.2.2]
at play.api.DefaultApplication.handleError(Application.scala:399) [play_2.10.jar:2.2.2]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$2$$anonfun$applyOrElse$3.apply(PlayDefaultUpstreamHandler.scala:261) [play_2.10.jar:2.2.2]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$2$$anonfun$applyOrElse$3.apply(PlayDefaultUpstreamHandler.scala:261) [play_2.10.jar:2.2.2]
at scala.Option.map(Option.scala:145) [scala-library.jar:na]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$2.applyOrElse(PlayDefaultUpstreamHandler.scala:261) [play_2.10.jar:2.2.2]
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [controllers.Application] is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:296) ~[spring-beans.jar:3.2.3.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1125) ~[spring-context.jar:3.2.3.RELEASE]
at Global.getControllerInstance(Global.java:21) ~[na:na]
at play.core.j.JavaGlobalSettingsAdapter.getControllerInstance(JavaGlobalSettingsAdapter.scala:46) ~[play_2.10.jar:2.2.2]
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$1$$anonfun$apply$1.apply(routes_routing.scala:57) ~[na:na]
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$1$$anonfun$apply$1.apply(routes_routing.scala:57) ~[na:na]
Actually the controller itself should not be transactional, as transactionality is a concern of the service layer and not the presentation/web layer or the repository layer.
There are several reasons for this, for example the controller layer might trigger several business transactions. It's possible to make a controller transactional but it's not recommended practice, if you move the #Transactional annotation from the controller to the #Service layer, it will surely work.

Can't Autowire ServletContext

I'm new with Spring, and I'm trying to use the #Autowire annotation for the ServletContext with my class attribute:
#Controller
public class ServicesImpl implements Services{
#Autowired
ServletContext context;
I defined the bean for this class in my dispatcher-servlet.xml:
<bean id="services" class="com.xxx.yyy.ServicesImpl" />
But when I try to run a JUnit test it gives the following error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [javax.servlet.ServletContext] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I thought that the ServletContext injection was automatic with spring... How can I solve this?
Thanks!
EDIT: I want to use the servletContext to call the getRealPath() method. Is there any alternative?
Implement the ServletContextAware interface and Spring will inject it for you
#Controller
public class ServicesImpl implements Services, ServletContextAware{
private ServletContext context;
public void setServletContext(ServletContext servletContext) {
this.context = servletContext;
}
You'll probably want to take a look at MockServletContext which can be used in unit tests.
ServletContext is not a Spring bean and it can, therefore, not be injected unless you implement ServletContextAware.
If one thinks in modules or layers then the servlet context shouldn't be available outside the web module/layer. I suppose your ServicesImpl forms part of the business or service layer.
If you gave a little more context we might be able to suggest better alternatives.

Resources