2

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)}
user124
  • 423
  • 2
  • 7
  • 26
  • Have you added the @Component at the `entityManagerFactory` or at least mark it as `@Qualifier("entityManagerFactort)` ?? Just asking :) If not let me know so I can explain more with an answer – Aris Mar 26 '21 at 09:35
  • @user124 I have updated my answer. Check this again – Panagiotis Bougioukos Mar 26 '21 at 10:03

2 Answers2

2

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;
Panagiotis Bougioukos
  • 15,955
  • 2
  • 30
  • 47
  • Yeah, I think this is also an option but he can manage it with the annotations. `@Qualifier` `@Component`. But yes this is called `Autowiring by name` :) – Aris Mar 26 '21 at 09:43
  • @Boug ,i tried but same error, please see update in answer – user124 Mar 26 '21 at 10:02
  • @user124 in your question you have updated with my previous answer. Not this one here – Panagiotis Bougioukos Mar 26 '21 at 10:05
  • Not able to resolve still. The updated answer u gave, is something i already tried as I ,mentioned in question with the difference that the Qualifier annotation was using "value" parameter, but i tried with/without parameter, still it did not work. – user124 Mar 26 '21 at 10:16
  • @user124 check closely. You have tried `@Bean(name="entityManagerFactory")`. What I say is the name you tried `entityManagerFactory` as name is already taken. Therefore it fails. You should try changing the name to something else, like `customEntityManagerFactory` – Panagiotis Bougioukos Mar 26 '21 at 10:17
  • how u know "entityManagerFactory" is already taken? The logs did not reflect that – user124 Mar 26 '21 at 10:24
  • okay it resolved.but still how do u know that "entityManagerFactory" is already taken? – user124 Mar 26 '21 at 10:29
  • 1
    Look how I know, it was the only possible solution after eliminating all others :D. Except from that the logs does not show any error because of a property called `spring.main.allow-bean-definition-overriding=true` which allows that. If you turn that to false something must come to logs – Panagiotis Bougioukos Mar 26 '21 at 10:30
1

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

Aris
  • 984
  • 8
  • 22