Java/Spring Problem with #Service and #Autowired annotations - java

[spring 3.0.5]
[jboss 5.1]
I have several classes labeled as #Service, which implements thet same interface.
For example,
#Service(value="test1")
public TestImpl1 implements Test {}
#Service(value="test2")
public TestImpl2 implements Test {}
Next, I have the following structure
public SomeClass {
#Autowired
#Qualifier("test1")
Test test1;
#Autowired
#Qualifier("test2")
Test test2;
I am getting an exception (at deployment)
10:36:58,277 ERROR [[/test-web]] Servlet /test-web threw load()
exception
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
unique bean of type [pl.tests] is defined: expected single matching
bean but found 2: [test1, test2]
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.doReso lveDependency(DefaultListableBeanFactory.java:
796)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolv eDependency(DefaultListableBeanFactory.java:
703)
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostPro cessor
$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:
474)
Anyone know how to solve this?
T.

A few options:
Use #Resource(name="test1") in the injection point
can use the javax.inject.Qualifer mechanism. In short - you define an annotation (#Test) and annotate the annotation with #Qualifier. Then use #Autowired #Test on the injection point.
explicitly set qualifiers on the target bean. The docs say show only the xml version <qualifier />, but try adding #Qualifier("test1") on the service definition
Here is the documentation about it

Related

Spring Autowiring - if object name needs to be same as beanId always?

I have defined bean in spring configuration something like -
<bean id="xyz" class="com.foo.Test">
and the class where I am using the bean is
package com.bar;
import com.foo.Test;
Class Demo {
#Autowired
Test xyz;
//Do operations of Test using abc now
}
what I am asking I tried below and it worked fine.
package com.bar;
import com.foo.Test;
Class Demo {
#Autowired
Test abc;
//Do operations of Test using abc now
}
So if keeping the bean id same as object name doesn't matter ?
Thanks.
If you autowire a bean and the spring context defines exactly one bean which is assignment compatible with the type you wire the bean to (in your case Test) then spring does not require any additional information.
If the spring context does define more than one bean which is assignment compatible with the type you wire the bean to you have to add the annotation #Qualifier and specify the identifier like this:
#Autowired
#Qualifier("xyz")
Test abc;
Spring Framework Reference Documentation:
#Autowired
#Qualifier

Unsatisfied dependency expressed through field 'fooService': No qualifying bean of type [aaa.FooService] found for dependency [aaa.FooService]

I have encountered this weird behavior of Spring in Spring boot 1.4.0. Spring basically tells me that it cannot autowire a bean to the resource, because it did not found itself for dependency.
UnsatisfiedDependencyException: Error creating bean with name 'restResource': Unsatisfied dependency expressed through field
'fooService': No qualifying bean of type [**aaa.FooService**] found for dependency [**aaa.FooService**]
FooService is autowired in the resource. When I #Autowire it into #Configuration file, which creates the resource, it is injected there as expected.
This works:
public class ServiceMocksRestConfig extends WebMvcConfigurerAdapter {
#Autowired
private FooService fooService; //instance here
#Bean
public FooResource fooResource() {
return new FooResource(); // debuger stop here
}
//Debugger step into
#RestController
public class FooResource {
#Autowired
private FooService fooService; //bang
Does someone has any idea, what might went wrong?
Funny stuff is that when I run the app from tests using boot spring runner, it also works (everything, including this resource)
I managed today to find the root cause. Its Spring Boot devtools - more precisely its split classloader (related bug: https://github.com/spring-projects/spring-boot/issues/3316)
When I put a breakpoint in ListableBeanFactory when the child REST #Configuration was about to #Autowire the FooService
and did FooService instanceof FooServiceInterface, it returned false.
And when I did FooService.class.getClassLoader() and beanfactory.getBean("fooService" /cannot use class here, would trigger not found exception/).getClass().getClassloader() these were different (one was AppClassLoader and the other was devtools restartable class loader).
Solution: remove boot devtools from classpath.
The exact reason for this is that, there is no bean initialized for type FooService inside the Spring IOC container at the moment the run-time tries to autowire FooService into ServiceMocksRestConfig .
It can be cause by different mistakes in development. This article addresses each and every possible mistakes that can cause this problem.

Spring why isn't this autowired class, autowiring into itself [duplicate]

I tried the following code with Spring 3.x which failed with BeanNotFoundException and it should according to the answers of a question which I asked before - Can I inject same class using Spring?
#Service
public class UserService implements Service{
#Autowired
private Service self;
}
Since I was trying this with Java 6, I found the following code works fine:
#Service(value = "someService")
public class UserService implements Service{
#Resource(name = "someService")
private Service self;
}
but I don't understand how it resolves the cyclic dependency.
EDIT:
Here's the error message. The OP mentioned it in a comment on one of the answers:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.spring.service.Service] 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)}
Update: February 2016
Self autowiring will be officially supported in Spring Framework 4.3. The implementation can be seen in this GitHub commit.
The definitive reason that you cannot autowire yourself is that the implementation of Spring's DefaultListableBeanFactory.findAutowireCandidates(String, Class, DependencyDescriptor) method explicitly excludes the possibility. This is visible in the following code excerpt from this method:
for (String candidateName : candidateNames) {
if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
result.put(candidateName, getBean(candidateName));
}
}
FYI: the name of the bean (i.e., the bean that's trying to autowire itself) is beanName. That bean is in fact an autowire candidate, but the above if-condition returns false (since candidateName in fact equals the beanName). Thus you simply cannot autowire a bean with itself (at least not as of Spring 3.1 M1).
Now as for whether or not this is intended behavior semantically speaking, that's another question. ;)
I'll ask Juergen and see what he has to say.
Regards,
Sam (Core Spring Committer)
p.s. I've opened a Spring JIRA issue to consider supporting self-autowiring by type using #Autowired. Feel free to watch or vote for this issue here: https://jira.springsource.org/browse/SPR-8450
This code works too:
#Service
public class UserService implements Service {
#Autowired
private ApplicationContext applicationContext;
private Service self;
#PostConstruct
private void init() {
self = applicationContext.getBean(UserService.class);
}
}
I don't know why, but it seems that Spring can get the bean from ApplicationContext if is created, but not initialized. #Autowired works before initialization and it cannot find the same bean. So, #Resource maybe works after #Autowired and before #PostConstruct.
But I don't know, just speculating. Anyway, good question.
By the way, the more elegant solution to the self-invocation problem is to use AspectJ Load-Time Weaving for your transactional proxies (or whatever AOP-introduced proxy you're using).
For example, with annotation-driven transaction management, you can use the "aspectj" mode as follows:
<tx:annotation-driven mode="aspectj" />
Note that the default mode is "proxy" (i.e., JDK dynamic proxies).
Regards,
Sam
Given above code I don't see a cyclic dependency.
You injecting some instance of Service into UserService.
The implementation of the injected Service does not necessarily need to be another UserService so there is no cyclic dependency.
I do not see why you would inject a UserService into UserService but I'm hoping this is a theoretic try out or such.
Get AOP proxy from the object itself question suggests alternative hacky approach with AopContext.currentProxy() that may be suitable for special cases.
Just another aproach:
#EnableAsync
#SpringBootApplication
public class Application {
#Autowired
private AccountStatusService accountStatusService;
#PostConstruct
private void init() {
accountStatusService.setSelf(accountStatusService);
}
}
#Service
public class AccountStatusService {
private AccountStatusService self;
public void setSelf(AccountStatusService self) {
this.self = self;
}
}
with this your service will be in proxy. I did this to work with async methods inside itself.
I have tryied #sinuhepop solution:
#PostConstruct
private void init() {
self = applicationContext.getBean(UserService.class);
}
It did a injection but the service wasn't inside proxy and my methods wasn't running on a new thread. With that aproach it works as i would like.
It looks like spring creates and configures an object and then places it in the bean look up context. But, in the case of Java, I think it creates the object and ties it to the name and the during configuration when the object is looked up by the name it is found in the context.
This is my solution for small to medium sized projects. No AspectJ or application context magic, it works with singletons and constructor injection and is very easy to test.
#Service
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class PersonDao {
private final PersonDao _personDao;
#Autowired
public PersonDao(PersonDao personDao) {
_personDao = personDao;
}
}

Strange spring-boot behaviour when trying to autowire javax.validation.Validator

Here's my problem:
I develop a web application based on spring-boot, the autowired annotation of spring works in every layers except for this interface "javax.validation.Validator".
When I'm trying to autowired "javax.validation.Validator" in my validator like this:
#Component
public class BrandValidator{
#Autowired
private javax.validation.Validator validator;
I've got this exception: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.validation.Validator] found for dependency
First I was thinking that no bean was available for this class in the spring context but actually when I list the bean available at the run time (after commenting the Autowired annotation on my validator) I see that this bean is available :
"mvcValidator" with the following type OptionalValidatorFactoryBean (this class extend LocalValidatorFactoryBean and LocalValidatorFactoryBean implements javax.validation.Validator and org.springframework.validation.Validator you can see here http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html)
I have try to add the #Qualifier(value ="mvcValidator") annotation but I got the same exception.
The strange part is that I m able to autowire the "spring" validator (org.springframework.validation.Validator) class perfectly well :
#Autowired
private org.springframework.validation.Validator validatorSpring;
I see in debug mode that the OptionalValidatorFactoryBean present in the context is injected.
And finally if I autowire org.springframework.validation.Validator just before javax.validation.Validator like this :
#Component
public class BrandValidator{
//workaround
#Autowired
private org.springframework.validation.Validator validatorSpring;
#Autowired
private javax.validation.Validator validator;
Now javax.validation.Validator is correctly injected(In debug mode I see that both validators the same object OptionalValidatorFactoryBean). I really don't understand what is going when the context is loaded and I really don't like this workaround (I don't need org.springframework.validation.Validator in my class).
Any idea how correctly inject javax.validation.Validator with spring boot ?
Try adding a #DependsOn(value="mvcValidator") on the BrandValidator class.

How to add inner classes to Spring application context for Unit Testing?

I have a bean whose business logic loads beans of a certain type from the ApplicationContext in order to process them.
For my jUnit tests, I would like to create some dummy beans within my unit test class and see if my bean under test properly processes them. However, I am not sure what the best way to accomplish this is.
If I just declare my inner class within my test class, Spring will not have it as part of its application context. I realize that I could inject my application context within my jUnit class, and then use appContext.registerPrototype() to add it, however, I thought there might be a cleaner way using annotations.
I've tried to annotate the internal class with #Component, but not surprisingly, it did not work.
public class PatchEngineTest extends TestBase {
#Component
protected class Patch1 extends PatchBaseImpl implements Patch{
public void applyPatch() throws Exception {
// does nothing
}
}
#Autowired PatchRepository patchRepository;
#Autowired Patch1 patch1;
#Test
public void test() {
fail("Not yet implemented");
}
}
Not surprisingly, I get the following error message:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.ia.patch.PatchEngineTest$Patch1] 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)}
Is there any way of doing this?
You need to make your inner class static; Spring can't instantiate a non-static inner class as a bean. If there really is a valid reason why it needs to be non-static, you could create it manually in an #Bean method.
I also met this problem, and below is my solution :
#RunWith(SpringRunner.class)
#SpringBootTest
#ComponentScan
#ImportAutoConfiguration
public class FooTest {
#Component
public static class Bar {
}
}
I used spring boot 2.1.4.RELEASE

Categories

Resources