I have been studying #Produces annotation of CDI dependency injection from here. I just created my own same example. However, I am facing with ambiguous dependency.
public interface Bank {
public void withdrawal();
public void deposit();
}
public class BankOfAmerica implements Bank {
#Override
public void withdrawal() {
System.out.println("Withdrawal from Bank of America");
}
#Override
public void deposit() {
System.out.println("Deposit to Bank of America");
}
}
public class BankFactory {
#Produces
public Bank createBank() {
return new BankOfAmerica();
}
}
And this is the class which bean is get injected.
public class ProducesExample {
#Inject
private Bank bankOfAmerica;
public void callBanksWithdrawal() {
bankOfAmerica.withdrawal();
}
}
I appreciate for any help.
EDIT: I know this a kind of duplicate of this question. However, in the tutorial which I shared, it says it should work. Moreover, there is only one type of bean so no need use #Default or #Alternatives but still get confused about why it is not working.
The tutorial is a bit ambiguous (pun intended) about which classes should be deployed simulataneously in each step, so I wouldn't worry about that too much.
The answer to the other question you linked does match your case. BankOfAmerica is a bean of type Bank (in CDI 1.0 or in CDI 1.1+ with explicit beans), and your producer method is another bean of the same type, hence the ambiguous resolution.
One thing that can be helpful is your beans.xml file.
If you want to have a factory (using #produces) you cannot have the bean-discovery-mode="all". If you have the all option than you will get Ambiguous dependencies exception cause all your implementations will be auto scanned as possible dependencies ( what in my opinion is a bad performance option ).
So put bean-discovery-mode="annotated" , leave your implementations cdi-annotation free and use #Dependent in the factory and #produces in the build method.
You have to add #BankProducer annotation like that :
public class BankFactory {
#Produces
#BankProducer
public Bank createBank() {
return new BankOfAmerica();
}
}
Related
Hi i have a rather specific question regarding Spring Aspects that leaves me puzzled. I played around with Springs and Apsects and and tried out a very simple Example to see how it works:
#Component
public class Comment {
private String text;
private String author;
public String get() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
#Aspect
public class LoggingAspect {
#Around("execution(* aop.beans.*.*(..))")
public void log(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Start Aspect for method: " + joinPoint.getSignature());
joinPoint.proceed();
}
}
My configuration file:
#Configuration
#ComponentScan("aop.beans")
#EnableAspectJAutoProxy
public class ProjectConfig {
#Bean
public LoggingAspect aspect() {
return new LoggingAspect();
}
}
With that i used a simple Main method to play around with the concept a little:
public class Main {
public static void main(String[] args) {
#SuppressWarnings("resource")
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProjectConfig.class);
context.registerShutdownHook();
CommentService service = context.getBean(CommentService.class);
Comment comment = context.getBean(Comment.class);
comment.setAuthor("Andreas");
comment.setText("Hallo.");
service.publishComment(comment);
System.out.println(service.getClass());
}
}
This worked fine but something strange happens when ich change the hirarchy of the comment class. I wanted to see what happens if the class implements a generic interface so i changed it as follows
public class Comment implements Supplier<String>
I immediately get an error with the following stack trace:
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'aop.beans.Comment' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1172)
at aop.Main.main(Main.java:17)
This left me wondering why that is? If i remove the generic superinterface or the aspect bean everthing works fine but both things together do not seem to fare well. Can someone provide an explanation? Is Spring not able to create a Proxy object if the class has a generic superclass?
Edit: The solution is in the comments :) i found further documentation on the mechanism in Spring Proxy Mechanism Documentation
This happens because of the way Spring implements AOP.
When proxied class (Comment in your case) doesn't implement any interfaces, CGLib proxy is used. Basically, it generates a class which is subclass of proxied class. Thus, you can getBean by parent's class.
When there are implemented interfaces, Spring uses JDK dynamic proxies which don't extend the proxy class, but implement all its interfaces, thus you can't find a bean by it's class.
That's why it's always a good practice to autowire your beans by interface rather then by class.
Solution
You can force Spring to use CGLib proxies for AspectJ by annotating you configuration class #EnableAspectJAutoProxy(proxyTargetClass = true).
If you want to use JDK Dynamic proxies, create interface for Comment and then use context.getBean(YourInterfaceName.class).
I have a Hibernate entity which has a listener attached using the #EntityListeners annotation
#Entity
#EntityListeners(value = UpdateListener.class)
public class User
{
//fields
}
This listener looks like this
#Slf4j
public class UpdateListener {
private final TestDep testDep;
public UpdateListener(TestDep testDep) {
this.testDep = testDep;
}
#PrePersist
void preCreate(User taxonomy) {
log.info("pre create");
}
#PostUpdate
void postUpdate(User taxonomy) {
log.info("post update");
}
}
I thought this might be a problem since there isn't a no-argument constructor but, to my surprise, Spring actually has no problem with it and will autowire the constructor just as it would for a bean. TestDep just looks like this, by the way
#Component
public class TestDep {}
The problem I have that IntelliJ does not understand that this constructor is autowired, so it does not give any suggestions about where the dependency comes from. Usually there's a green circle with a slash through it when it's able to infer the relationship.
I tried marking the constructor as #Autowired but it doesn't help IntelliJ to understand what's going on, and in fact sparks a warning (which makes sense)
#Autowired // WARNING: Autowired members must be defined in valid Spring bean (#Component|#Service|...)
public UpdateListener(TestDep testDep) {
this.testDep = testDep;
}
If I make the listener a #Component, I get the dependency hints but Spring instantiates it twice, once via #Component and once via #EntityListeners.
Is there another way I can approach this?
Person.java
#Controller
public class Person
{
#Autowired
private Ability ability;
public void printMessage(){
ability.printMessasge();
}
public void setOutputGenerator( Ability ability) {
this.ability = ability;
}
}
Ability.java
#Controller
public class Ability
{
void printMessasge(){
System.out.println("I print message");
}
}
spring.xml
<bean id="invisible" class="com.mkyong.common.Ability" >
</bean>
<context:component-scan base-package="com.mkyong" />
App.java
public class App {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"spring.xml");
Person person = (Person) context.getBean("person");
person.printMessage( );
}
In the above example i have defined two beans of Ability class one using #Controller and one in xml file. According to Autowire by type i should get
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException:
...
No unique bean of type [com.mkyong.common.Ability] is defined:
But i am getting proper output. Why?
And if i create an interface which Ability class implements then i would get UnsatisfiedDependencyException exception. Like this:
Parent.java
public interface Parent{
public void printMessasge();
}
Ability.java
#Controller
public class Ability implements Parent
{
void printMessasge(){
System.out.println("I print message");
}
Person.java
#Controller
public class Person
{
#Autowired
Parent parent;
public void printMessage(){
parent.printMessasge();
}
public void setOutputGenerator( Parent parent) {
this.parent= parent;
}
}
By default Spring indeed matches by type, but in case of multiple matching beans, it falls back to matching by name. The reference (6.9.4 Fine-tuning annotation-based autowiring with qualifiers) says:
For a fallback match, the bean name is considered a default qualifier value.
Using the #Qualifier annotation makes the autowiring by type and additionally by name more explicit.
You are not going to get a UnsatisfiedDependencyException with this configuration because Spring is smart enough to also look at the name of your required dependency, as #Adam writes in his answer. So even if the default autowiring mode is by type and there are two beans of the same type for that dependency, Spring is able to solve the conflict.
This behavior is described in the official documentation, 6.9.4 Fine-tuning annotation-based autowiring with qualifiers section.
More details about autowiring modes can be found 6.4.5 Autowiring collaborators.
If you change the name of Person.ability field to something else, like Person.ability2, then Spring will throw a org.springframework.beans.factory.NoUniqueBeanDefinitionException. It cannot decide which bean it should wire for the Person.ability2 field because:
There are two beans of com.mkyong.common.Ability type in the context
Field name does not match with either bean names
EDIT: in the second case you mention (with the interface), Spring throws the exception for the same bean naming reason I explained above.
Official documentation references:
6.4.5 Autowiring collaborators
6.9.4 Fine-tuning annotation-based autowiring with qualifiers
you have two ambiguous beans defined, when spring try find the bean via type it finds two beans, one via scan other explicitly defined in spring.xml. use #Qualifier to mark the correct bean loaded in Person class. So probably you want like this,
#Controller
public class Person
{
#Autowired
#Qualifier("invisible")
private Ability ability;
public void printMessage(){
ability.printMessasge();
}
public void setOutputGenerator( Ability ability) {
this.ability = ability;
}
}
I am learning Java EE CDI, dependency injection, and #Produces in particular. I am wondering why in getGreedingCard() method, it needs a #Produces annotation at all, since the two classes GreetingCardImpl and AnotherGreetingCardImpl are already imported into the space. This is just like the regular package/class dependency and a simple import solves the problem. Why does it need a dependency injection through a #producer annotation?
Thanks for explanation in advance.
public interface GreetingCard {
void sayHello();
}
public class GreetingCardImpl implements GreetingCard {
public void sayHello() {
System.out.println("Hello!!!");
}
}
public class AnotherGreetingCardImpl implements GreetingCard {
public void sayHello() {
System.out.println("Have a nice day!!!");
}
}
import com.javacodegeeks.snippets.enterprise.cdibeans.impl.AnotherGreetingCardImpl;
import com.javacodegeeks.snippets.enterprise.cdibeans.impl.GreetingCardImpl;
#SessionScoped
public class GreetingCardFactory implements Serializable {
private GreetingType greetingType;
#Produces
public GreetingCard getGreetingCard() {
switch (greetingType) {
case HELLO:
return new GreetingCardImpl();
case ANOTHER_HI:
return new AnotherGreetingCardImpl();
default:
return new GreetingCardImpl();
}
}
}
I am wondering why in getGreedingCard() method, it needs a #Produces
annotation at all, since the two classes GreetingCardImpl and
AnotherGreetingCardImpl are already imported into the space.
Well, it's not that getGreetingCard needs the #Produces annotation. The point is to enable other classes to recieve GreetingCards via Dependency Injection.
public class Foo {
#Inject // <--- will invoke #Producer method
GreetingCard foosGreetingCard
...
}
See here for more details:
A producer method is a method that acts as a source of bean instances.
The method declaration itself describes the bean and the container
invokes the method to obtain an instance of the bean when no instance
exists in the specified context.
In your case it doesn't need #Produces as you will be injecting factory bean and using its method directly to create instances, and not injecting the greetingCard beans themseleves.
#Inject
GreetingCardFactory factory;
...
GreetingCard card = factory.getGreetingCard();
If you would define it as #Produces method, and the try to inject GreetingCard, then you would get exception that I've described in the comment.
However, if you would additionally create qualifier, like this:
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
public #interface ProducedCard {}
and add it to the producer method:
#Produces #ProducedCard
public GreetingCard getGreetingCard() {
...
then you would be able to inject just GreetingCard beans using your producer method like this:
#Inject #ProducedCard
GreetingCard card;
since now there is no ambiguity, as there is only one place to create greeting cards marked with #ProducedCard :-)
No one so far was capable of providing a working correct example of interface injection in Spring Framework.
Martin Fowler article is not for mortals, everything else just words positioned in a very confusing way. I have surfed over THIRTY articles, where people either tell "Spring doesn't directly supports for interface injection"("and because I don't know exactly how I will only describe setter and constructor injections") or either "I will discuss it in my other threads" or either there will be few comments below saying that it is wrong example. I don't ask for explanation, I BEG for example.
There are three types of injection: Constructor, Setter and Interface. Spring doesn't support the latest directly(as I have observed people saying). So how is it done exactly?
Thank You,
According to Variants of DI in spring
DI exists in two major variants, Constructor-based dependency injection and Setter-based dependency injection.
Also see Interface injection is not implemented in Spring clearly states it.
So there are only two variants of DI. So if documentation says nothing about interface injection, its clear that its not there. Those who believe that interface injection is done by providing setter method in interface answer me:
Why spring ref doc left mention of interface injection?
Why can't interface injection via providing setter method NOT considered as setter injection itself. Why create special term for that when introduction of interface doesn't affect anything, I mean its still configured the same way. If they were different then how can one find it via seeing the config. Shouldn't it be transparent that in config and not seeing the impl that actually configured class implements some interface ?
Just like Instantiation using an instance factory method and Instantiation using an static factory method, some bean attributes should clarify the interface injection?
With interface injection an interface explicitly defines the point where a dependency can be set:
interface InjectPerson {
public void injectHere(Person p);
}
class Company implements InjectPerson {
Person injectedPerson;
public void injectHere(Person p) {
this.injectedPerson = p;
}
}
There are 3 types of dependency injections:-
1. Constructor Injection(E.g Pico Container, Spring supports it).
2. Setter Injection(E.g Spring supports it).
3. Interface Injection(E.g Avalon, Spring does not support it).
Spring supports only constructor and setter based injection.
Looks like you got confused in the different types(3) and what spring supports(2 of them).
Hi I tried with a very simple approach that may clarify your answer.
following is the code that i have built on using two interfaces and and two bean classes.
first interface with name Job.
public interface Job {
public void setmyJob(String myJob);
public String getmyJob();
}
and one class to implement this interface with name as MyJob
public class MyJob implements Job {
public String myJob;
public MyJob() {
System.out.println("From MyJob default Constructor and the ID= "+this);
}
public void setmyJob(String myJob) {
this.myJob=myJob;
}
public String getmyJob() {
return myJob;
}
}
In the next step i created another Interface with name as Service
public interface Service {
public void setJob(Job job);
public Job getJob();
}
and then again another class to implement this Service Interface.
public class MyService implements Service {
public Job job;
public void setJob(Job job) {
this.job=job;
System.out.println("Hello from Myservice: Job ID="+job);
}
public Job getJob() {
return job;
}
}
then i created on main class with the main function and written the code as follows:
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApplication {
public static void main(String...a) {
BeanFactory beanfactory=new ClassPathXmlApplicationContext("Beans.xml");
MyService myservice=(MyService)beanfactory.getBean("myservice");
System.out.println("Before print");
System.out.println(myservice.getJob().getmyJob());
}
}
in my Beans.xml file i mentioned the code as follows and it worked.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="myjob" class="MyJob">
<property name="myJob" value="My First String"/>
</bean>
<bean id="myservice" class="MyService">
<property name="job" ref="myjob"/>
</bean>
</beans>
I have also reffered to another online tutorials and then got this kind of solution. please let me know if you have any problem with this code. it is working for me.
I think, that the confusion around interface injection is caused by missunderstanding what the term "interface injection" actually means. In my understanding, interface injection describes the ability of a bean contener to inject a new interface to the bean, no matter that the class definition of this bean is not implementing it.
All examples presented here show how to create a bean out of concrete class, and then how to inject it into another bean. The fact, that in all cases bean is injected into a field defined as an interface does not matter- all operations are done with beans created out of concrete instances.
I can provide also another catchy example:
package creditCards;
interface PaymentCard {
Boolean isDebitAllowed();
}
<bean id="card" class="creditCards.PaymentCard">
<lookup-method name="isDebitAllowed" bean="boolValue"/>
</bean>
<bean id="boolValue" class="java.lang.Boolean">
<constructor-arg type="boolean" value="true"/>
</bean>
As you see here, it is even possible to create a bean out of interface! Still, it is not a interface injection, as IoC contener initializes instanse of this bean by its own. In other words, card bean is an initialized object, not an interface, what makes, that the selected answer for this question is correct.
I think someone answered your questions here
I also didn't know what Interface injection is until I read this statement from "Pro Spring MVC with web flow book"
"Note that interface-based dependency injection isn’t supported by the Spring Framework. This
means that we need to specify which concrete implementation to inject for a certain interface."
Please check the below example for iterface injection.
There is a shape interface and 2 concrete classes which imiplements shape namely square and rectangle.
The interface
package di.interfaceinjection;
public interface Shape {
public String shapeName();
public void displayName();
}
2 Implemented classes
package di.interfaceinjection;
public class Square implements Shape {
#Override
public String shapeName() {
return "Square";
}
#Override
public void displayName() {
System.out.println("Square");
}
}
package di.interfaceinjection;
public class Rectangle implements Shape{
#Override
public String shapeName() {
return "Rectangle";
}
#Override
public void displayName() {
System.out.println("Rectangle");
}
}
Now, we have a class which sets the shape.
public class ShapeSetter {
private Shape shape;
public Shape getShape() {
return shape;
}
public void setShape(Shape shape) {
this.shape = shape;
}
}
and finally the configuration
<bean id="shape1" class="di.interfaceinjection.ShapeSetter">
<property name="shape" ref="square"></property>
</bean>
<bean id="shape2" class="di.interfaceinjection.ShapeSetter">
<property name="shape" ref="rectangle"></property>
</bean>
<bean id="square" class="di.interfaceinjection.Square"></bean>
<bean id="rectangle" class="di.interfaceinjection.Rectangle"></bean>
Here,
we are injecting different shapes.
package di.interfaceinjection;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class InterfaceInjeection {
/**
* #param args
*/
public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext("intro.xml");
ShapeSetter shape = (ShapeSetter)appContext.getBean("shape2");
shape.getShape().displayName();
}
}