2

I have the following setup:

@Component public class ImplOne implements IFace{ } @Component public class ImplTwo implements IFace{ } public interface IFace{ } 

I am trying to get a reference of ImplOne by type:

@RunWith(SpringJUnit4ClassRunner.class) public class ImplOneTest { @Autowired private ImplOne impl; @Test public void test(){ Assert.assertNotNull(impl); } } 

Though with this I get the following exception:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [some.package.TestBean] 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 tried the following workarounds:

  • Remove "implements IFace" from ImplOne so the implementation class itself gets Proxied by cglib. Not acceptable because I also need to be able to get all implementations of IFace in my application code.
  • Doing method injection via a @Autowired public void setImplOne(IFace[] beans) and filtering the instance through instanceof check does not work, because the injected beans are subclasses of type java.lang.reflect.Proxy which doesn't offer any useful methods.
  • Changing @Component of ImplOne to @Component("implone") and using @Qualifier("implone").

Code:

@RunWith(SpringJUnit4ClassRunner.class) public class ImplOneTest { @Autowired @Qualifier("implone") private ImplOne impl; @Test public void test(){ Assert.assertNotNull(impl); } } 

But I don't like the idea of having to name my beans just to be able to inject the concrete implementation.

Is there some way to do this elegantly, or atleast in some manner that only affects my test code? Also is there some special reason why my first example is unsupported?

3
  • The exception suggests that the problem is not with the ImplOne reference but with a de.investdwin.gemeinsam.abstrakt.TestBean reference that can not be found. Any chance you are missing one of those somewhere in your Spring configuration? Commented Dec 10, 2009 at 18:53
  • i renamed the bean when posting this question, originally it was TestBean Commented Dec 12, 2009 at 11:07
  • I tried naming the bean and use the @Qualifier and it didn't work. I even have just one concrete implementation. @Qualifier is only used to resolve ambiguity if there's any, otherwise it would be ignored. Therefore using @Qualifier doesn't make any difference unless you have more than one implementation. I wonder how could you possibly make it work since the problem is not ambiguity but simply there's no even a bean with the specified matching type. Commented Dec 17, 2012 at 7:57

3 Answers 3

3
  1. Check if the exception is about the beans you think it is. Because the names don't match
  2. Even if 1 is fixed, it is preferable to autowire by interface, not by concrete implementation. Most often (I can' know if this is true in your case), concrete implementations are proxied by spring (for transaction support, for example), and can be injected by interface only. And since you have two implementations of one interface, you have to provide a name, and either use @Autowired + @Qualifier, or use @Resource(name="") to inject what you want. And there is nothing wrong with this.
Sign up to request clarification or add additional context in comments.

2 Comments

Or put primary="true" on the preferred bean definition, or autowire-candidate="false" on the other one
hmm, every bean would be primary="true" then, though isnt this xml-only? Seems like i am stuck with the names. i might use public static final String NAME = "implOne" and reference that in the annotations, so i dont't have two places to maintain those names.
1

Ok, today i found a way to make this work afterall. Seems like the Spring-AOP-Autoproxy was to blame for this not to work.

Currently I am using AJDT in Eclipse for compile time weaving (CTW) and the TransactionAnnotationAspect. I also removed the aspectjweaver and cglib dependency in my project, so autoproxy is not even supported anymore, after removing the following config part from applicationcontext:

<aop:pointcut id="serviceOperation" expression="execution(* some.package..*(..)) &amp;&amp; @target(org.springframework.stereotype.Service)" /> <aop:advisor pointcut-ref="serviceOperation" advice-ref="serviceTxAdvice" /> </aop:config> <tx:advice id="serviceTxAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*" read-only="true" propagation="SUPPORTS" /> </tx:attributes> </tx:advice> 

And that was also the reason why @Configurable didn't work for me...

Comments

1

Adding the following line worked for me:

<aop:aspectj-autoproxy proxy-target-class="true"/> 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.