Thursday, 11 May 2017

Spring: @Primary annotation example

If there are multiple beans available for the same type, spring don't know which bean to inject. You need to specify which bean to take, when more than one bean of same type are available. By using @Primary annotation, you can achieve this. @Primary indicates that a particular bean should be given preference when multiple beans are candidates to be autowired to a single-valued dependency.

Let me explain an example without @Primary annotation.

Author.java
package com.sample.pojo;

public class Author {
 private String firstName;
 private String lastName;
 private String dateOfBirth;
 private String country;

 public String getFirstName() {
  return firstName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public String getLastName() {
  return lastName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

 public String getDateOfBirth() {
  return dateOfBirth;
 }

 public void setDateOfBirth(String dateOfBirth) {
  this.dateOfBirth = dateOfBirth;
 }

 public String getCountry() {
  return country;
 }

 public void setCountry(String country) {
  this.country = country;
 }

 @Override
 public String toString() {
  StringBuilder builder = new StringBuilder();
  builder.append("Author [firstName=").append(firstName).append(", lastName=").append(lastName)
    .append(", dateOfBirth=").append(dateOfBirth).append(", country=").append(country).append("]");
  return builder.toString();
 }

}

ApplicationConfig.java
package com.sample.configurations;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.sample.pojo.Author;

@Configuration
public class ApplicationConfig {

 @Bean
 public Author getAuthor1() {

  System.out.println("Author bean is called");

  Author author = new Author();

  author.setFirstName("Chandra Mohan");
  author.setLastName("Jain");
  author.setDateOfBirth("11 December 1931");
  author.setCountry("India");

  return author;
 }

 @Bean
 public Author getAuthor2() {

  System.out.println("Author bean is called");

  Author author = new Author();

  author.setFirstName("Hari Krishna");
  author.setLastName("Gurram");
  author.setDateOfBirth("05 may 1989");
  author.setCountry("India");

  return author;
 }
}

HelloWorld.java
package com.sample.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.sample.configurations.ApplicationConfig;
import com.sample.pojo.Author;

public class HelloWorld {
 public static void main(String args[]) {
  ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);

  Author author1 = context.getBean(Author.class);
  Author author2 = context.getBean(Author.class);
  Author author3 = context.getBean(Author.class);

  System.out.println(author1);
  System.out.println(author2);
  System.out.println(author3);

  ((AnnotationConfigApplicationContext) context).close();
 }
}

Notify the class ‘ApplicationConfig’, I defined two methods getAuthor1, getAuthor2 which return Author instance. When you request spring for a bean of type Author, spring don't know which one to give. It throws NoUniqueBeanDefinitionException.

Run HelloWorld application, you will end up in following error.
Author bean is called
Author bean is called
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.sample.pojo.Author] is defined: expected single matching bean but found 2: getAuthor1,getAuthor2
 at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1031)
 at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)
 at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:335)
 at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1088)
 at com.sample.test.HelloWorld.main(HelloWorld.java:13)

How to resolve this error?
Keep @Primary annotation on top of any method getAuthor1 (or) getAuthor2. For example, I applied @Primary annotation on top of getAuthor1 method.

Update ApplicationConfig.java like below.


ApplicationConfig.java
package com.sample.configurations;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import com.sample.pojo.Author;

@Configuration
public class ApplicationConfig {

 @Bean
 @Primary
 public Author getAuthor1() {

  System.out.println("Author bean is called");

  Author author = new Author();

  author.setFirstName("Chandra Mohan");
  author.setLastName("Jain");
  author.setDateOfBirth("11 December 1931");
  author.setCountry("India");

  return author;
 }

 @Bean
 public Author getAuthor2() {

  System.out.println("Author bean is called");

  Author author = new Author();

  author.setFirstName("Hari Krishna");
  author.setLastName("Gurram");
  author.setDateOfBirth("05 may 1989");
  author.setCountry("India");

  return author;
 }
}

Re run HelloWorld.java application, you can able to see following output.
Author bean is called
Author bean is called
Author [firstName=Chandra Mohan, lastName=Jain, dateOfBirth=11 December 1931, country=India]
Author [firstName=Chandra Mohan, lastName=Jain, dateOfBirth=11 December 1931, country=India]
Author [firstName=Chandra Mohan, lastName=Jain, dateOfBirth=11 December 1931, country=India]


The corresponding bean definitions appear as follows.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

 <context:annotation-config />

 <bean id="author1" class="com.sample.pojo.Author" primary="true">
  <property name="firstName" value="Chandra Mohan" />
  <property name="lastName" value="Jain" />
  <property name="dateOfBirth" value="11 December 1931" />
  <property name="country" value="India" />
 </bean>

 <bean id="author2" class="com.sample.pojo.Author">
  <property name="firstName" value="Hari Krishna" />
  <property name="lastName" value="Gurram" />
  <property name="dateOfBirth" value="05 may 1989" />
  <property name="country" value="India" />
 </bean>

</beans>



Previous                                                 Next                                                 Home

No comments:

Post a Comment