Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Required Multiple beans of same type in Spring

A request before you mark it as duplicate. I have gone through the forum and couldn't find the solution for the problem anywhere.

I am writing a code using Spring 3.2 and everything is purely annotation based. The code receives XML files which are derived form different XSD files.

So we can say, there are five different XSD ( A1, A2, A3, A4, A5) and my code receives XML of any type, and I have the logic to identify the type of the XML upon arrival.

Now, I am trying to un-marshal these using Spring OXM. But because there are multiple XSDs involved, we cannot actually using one Un-marshaller. So we need around five of them.

In the Configuration class, I added five beans like below:

@Bean(name="A1Unmarshaller") public Jaxb2Marshaller A1Unmarshaller(){     Jaxb2Marshaller unMarshaller = new Jaxb2Marshaller();     unMarshaller.setContextPath("package name for the classes generate by XSD A1"); }  @Bean(name="A2Unmarshaller") public Jaxb2Marshaller A2Unmarshaller(){     Jaxb2Marshaller unMarshaller = new Jaxb2Marshaller();     unMarshaller.setContextPath("package name for the classes generate by XSD A2"); }  @Bean(name="A3Unmarshaller") public Jaxb2Marshaller A3Unmarshaller(){     Jaxb2Marshaller unMarshaller = new Jaxb2Marshaller();     unMarshaller.setContextPath("package name for the classes generate by XSD A3"); }  @Bean(name="A4Unmarshaller") public Jaxb2Marshaller A4Unmarshaller(){     Jaxb2Marshaller unMarshaller = new Jaxb2Marshaller();     unMarshaller.setContextPath("package name for the classes generate by XSD A4"); }  @Bean(name="A5Unmarshaller") public Jaxb2Marshaller A5Unmarshaller(){     Jaxb2Marshaller unMarshaller = new Jaxb2Marshaller();     unMarshaller.setContextPath("package name for the classes generate by XSD A5"); } 

Now I have five different classes C1, C2, C3, C4 and C5 and I am trying to inject one unmarshaller bean into one class. That means A1Unmarshaller is autowired to C1 and so on.

When the Spring context is built, it throws an error saying it expected one bean of type Jaxb2Marshaller and got five.

Note It worked fine when done using XML configuration, so I am not sure if I am missing something. Please help.

EDIT The code for one of the classes C1 is below:

@Component public class C1{  @Autowired private Jaxb2Marshaller A1Unmarshaller;     A1 o = null  public boolean handles(String event, int eventId) {     if (null != event&& eventId == 5) {                 A1 =  A1Unmarshaller.unMarshal(event);         return true;     }     return false; } 

}

like image 361
dharam Avatar asked Sep 10 '13 06:09

dharam


People also ask

Can we create multiple beans of same class in Spring?

It's not possible. You get a duplicate exception. It's also far from optimal with configuration data like this in your implementation classes. But you're using a separate factory for each different Spring bean you create.

Can we have multiple beans of a same type in a class?

The limitation of this approach is that we need to manually instantiate beans using the new keyword in a typical Java-based configuration style. Therefore, if the number of beans of the same class increases, we need to register them first and create beans in the configuration class.

How do you inject multiple beans of the same type?

The default autowiring is by type, not by name, so when there is more than one bean of the same type, you have to use the @Qualifier annotation.


2 Answers

You should qualify your autowired variable to say which one should be injected

@Autowired @Qualifier("A1Unmarshaller") private Jaxb2Marshaller A1Unmarshaller; 

The default autowiring is by type, not by name, so when there is more than one bean of the same type, you have to use the @Qualifier annotation.

like image 102
Bruce Lowe Avatar answered Oct 07 '22 17:10

Bruce Lowe


The Jaxb2Marshaller is perfectly capable to work with multiple different contexts/xsd. Simply specify multiple context paths by using the setContextPaths methods.

@Bean(name="A1Unmarshaller") public Jaxb2Marshaller A1Unmarshaller(){     Jaxb2Marshaller unMarshaller = new Jaxb2Marshaller();     unMarshaller.setContextPaths(         "package name for the classes generate by XSD A1",         "package name for the classes generate by XSD A2",         "package name for the classes generate by XSD A3",         "package name for the classes generate by XSD A4",         "package name for the classes generate by XSD A5" );     return unMarshaller; } 

That way you only need a single marshaller/unmarshaller.

Links

  1. Jaxb2Marshaller javadoc
  2. setContextPaths javadoc
like image 27
M. Deinum Avatar answered Oct 07 '22 17:10

M. Deinum