Spring @Bean Name, is not working with @Qualifier

Viewed 2573

I have a spring boot application. It creates LocalSessionFactoryBean Object and inject into session factory variable. It works fine as follow:

@Autowired
  @Qualifier(value="sessionFactory")
  private SessionFactory sessionFactory;


  @Primary
  @Bean
  public LocalSessionFactoryBean sessionFactory() {
    LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
    factory.setDataSource(dataSource);
    factory.setPackagesToScan(
        new String[] {
          "com.abc..entities",
          "com.abc.xyz.entities",
          "
        });
    factory.setHibernateProperties(hibernateProperties());
    return factory;
  }

However, I need to change bean Name of sessionFactory, which is default as function name, from sessionFactory to entityManagerFactory, so I did following:

  @Autowired
  @Qualifier(value="entityManagerFactory")
  private SessionFactory sessionFactory;


  @Primary
  @Bean(name="entityManagerFactory")
  public LocalSessionFactoryBean sessionFactory() {
    LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
    factory.setDataSource(dataSource);
    factory.setPackagesToScan(
        new String[] {
          "com.abc..entities",
          "com.abc.xyz.entities",
          "
        });
    factory.setHibernateProperties(hibernateProperties());
    return factory;
  }

But it throws error:

> Error creating bean with name 'XYZ': Unsatisfied dependency expressed
> through field 'sessionFactory'; nested exception is
> org.springframework.beans.factory.NoSuchBeanDefinitionException: No
> qualifying bean of type 'org.hibernate.SessionFactory' available:
> expected at least 1 bean which qualifies as autowire candidate.
> Dependency annotations:
> {@org.springframework.beans.factory.annotation.Autowired(required=true),
> @org.springframework.beans.factory.annotation.Qualifier(value=entityManagerFactory)}

I believe i did it correctly, what did I miss here?

Update :-

I tried following as mentioned in one of answer but it did not work:

@Autowired
  @Qualifier(value = "entityManagerFactory")
  private SessionFactory sessionFactory; 

and changed method as

@Primary
@Bean

public LocalSessionFactoryBean entityManagerFactory()
 { ..........},


>  Unsatisfied dependency expressed through field 'sessionFactory';
> nested exception is
> org.springframework.beans.factory.NoSuchBeanDefinitionException: No
> qualifying bean of type 'org.hibernate.SessionFactory' available:
> expected at least 1 bean which qualifies as autowire candidate.
> Dependency annotations:
> {@org.springframework.beans.factory.annotation.Autowired(required=true),
> @org.springframework.beans.factory.annotation.Qualifier(value=entityManagerFactory)}
2 Answers

What I think that happens here, is that entityManagerFactory is automatically registered from spring for another bean. Therefore you don't get what you ask for.

Try changing a little bit the name

@Bean(name="customEntityManagerFactory")
  public LocalSessionFactoryBean sessionFactory() {

and then

@Autowired
  @Qualifier("customEntityManagerFactory")
  private SessionFactory sessionFactory;

So let me give a high overview of all this @Autowire @Qualifier @Component...

@Autowire: This is A great way of making the injection in Spring explicit. But there are cases that Spring gets confused on which dependency to inject.

There comes the @Qualifier: You eliminate the ambiguity issue :) So even if Spring finds multiple beans to inject of the same type it knows which one to do so.

But if you want to use your specific implementation you need to specify that implementation with the @Component so the qualifier name will be used.

@Component("fooFormatter")
public class FooFormatter implements Formatter {
 
    public String format() {
        return "foo";
    }
}

And then:

public class FooService {
     
    @Autowired
    @Qualifier("fooFormatter")
    private Formatter formatter;
}

And there is another option as @Boug said in the above answer. Where you @Autowire by name. So the Spring will know that it must use the field name that is a match with the value of the @Component.

e.g.

public class FooService {
     
    @Autowired
    private Formatter fooFormatter;
}

I hope that all this makes sense :)

Here you can read more Check here

Related