Error: java.lang.IllegalArgumentException: Property 'transactionManager' is required even after it is declared - spring

I have already declared the transactionManager in my Config file as below.
#Bean
public HibernateTransactionManager transactionManager() {
return new HibernateTransactionManager(sessionFactory().getObject());
}
Even after the declaration, I see the error that Property 'transactionManager' is not found.
Trying to configure hibernate using Spring and Hibernate Contextual sessions.
Configured SessionFactory using LocalSessionFactoryBean.

Try to use interface instead of concrete class
#Bean
public TransactionManager transactionManager() {
return new HibernateTransactionManager(sessionFactory().getObject());
}

Related

Spring Data JPA - NoSuchBeanDefinitionException

I am using CURDRepository, when calling save menthod below exception got:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean named 'transactionManager' available: No matching
TransactionManager bean found for qualifier 'transactionManager' -
neither qualifier match nor bean name match!
whereas, when calling other function from repo like findALL and findByID they are working fine, below is code for config, repo and calling fucntion.
// config
#Primary
#Bean(name = "emfRequest")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("dsRequest") DataSource dataSource) {
return builder.dataSource(dataSource).packages("com.Digit4G.domain").build();
}
#Primary
#Bean(name = "tmRequest")
public PlatformTransactionManager transactionManager(
#Qualifier("emfRequest") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
// Repository
#Repository
public interface Digit4GRepo<P> extends CrudRepository<Digit4GRequest, Long> {
public List<Digit4GRequest> findBySUBNOAndIMEI(String subno, String IMEI);
public Digit4GRequest save(Digit4GRequest request);
}
// calling function
Digit4GRequest obj = new Digit4GRequest();
obj.setSUBNO(subno);
obj.setIMEI(IMEI);
obj.setIMSI(IMSI);
obj.setPACKAGENAME(packageName);
digit4GRepo.save(obj);

How to use Transactional annotation when config transactionManager conditionally in spring?

I use multiple datasources in my spring project.
I enable/disable them by manual config in project startup time.
At a time all of them may be active
So a transactionManager bean maybe active or not.
I implement it by #Conditional annotation in spring configuration class.
When I use a disable transactional annotation on methods I have NoSuchBeanDefinitionException.
When I define transactionManager bean conditionally how to use the transactional annotioan on methods?
The archiveTransactionManager bean doesn't create by #Conditional annotation and I want spring skip checking for bean validation of conditional transaction manager.
For conditional sessionFactory beans I set 'required' parameter in Autowired annotation to false for prevent spring to throw NoSuchBeanDefinitionException but what do I do for #Transactional ?
Configuration class
#Bean("archiveTransactionManager")
#Conditional(ArchiveCondition.class)
public HibernateTransactionManager archiveTransactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(archiveSessionFactory());
return transactionManager;
}
Transactional method
#Transactional(value = "archiveTransactionManager", readOnly = true)
private List<DocumentItem> loadArchivedDocumentItem() {...}
Usage
if(GeneralSetting.isArchive)
documentService.loadArchivedDocumentItem();
Current result:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'archiveTransactionManager' available: No matching PlatformTransactionManager bean found for qualifier 'archiveTransactionManager' - neither qualifier match nor bean name match!
I want spring skip bean validation of conditional transactionManager beans on some situations that they don't create by conditions.
I implement a no-op SessionFactory and instantiate it in spring configuration class whenever archive_mode is disable :
SpringConfig.java
#Bean("archiveSessionFactory")
public SessionFactory archiveSessionFactory() {
return ServerConf.ARCHIVE_MODE ? createNormalSessionFactory() : new DummySessionFactory();
}
#Bean("archiveTransactionManager")
public HibernateTransactionManager archiveTransactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(archiveSessionFactory());
return transactionManager;
}
DummySessionFactory.java
public class DummySessionFactory implements SessionFactory {
...
// These two methods call in spring initializing and we have to implement them
#Override
public Metamodel getMetamodel() {
return new MetamodelImpl(null);
}
#Override
public Map<String, Object> getProperties() {
return null;
}
//Throw suitable exception in other methods
#Override
public Session getCurrentSession() throws HibernateException {
throw new HibernateException("Desired mode is Disabled");
}
...
}
I would treat it as a fallback scenario, where you have to recover after a failure. In this case, have a method calling method annotated with
#Transactional(value = "archiveTransactionManager", readOnly = true)
in case of failure (or exception), call method annotated with
#Transactional(value = "alternativeTransactionManager", readOnly = true)
public void doSomething() {
try {
tryFirst();
} catch (Exception e) {
tryAlternative();
}
}
#Transactional(value = "archiveTransactionManager", readOnly = true)
public void tryFirst() {
}
#Transactional(value = "alternativeTransactionManager", readOnly = true)
public void tryAlternative() {
}
Keep in mind, you must have both of them declared though.
You used the wrong annotation to name the bean. #Qualifier is used on the injection point to specify the name. You need to give the bean a name with #Bean. So your bean definition needs to look like that:
#Bean("archiveTransactionManager")
#Conditional(ArchiveCondition.class)
public HibernateTransactionManager archiveTransactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(archiveSessionFactory());
return transactionManager;
}

Spring transaction configruation (bean vs inner class)

In examples from book Spring in action I found that configuration of TransactionManager is achieved by nested class:
#Configuration
#ComponentScan
public class JpaConfig {
//EntityManagerFactory, JpaVendorAdapter, DataSource #Beans
#Configuration
#EnableTransactionManagement
public static class TransactionConfig implements TransactionManagementConfigurer {
#Inject
private EntityManagerFactory emf;
public PlatformTransactionManager annotationDrivenTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
}
Is it a good practice or something? Is there any difference in comparison to standard #Bean approach like:
#Configuration
#EnableTransactionManagement
public class DbConfig {
//EntityManagerFactory, JpaVendorAdapter, DataSource #Beans
#Bean
public JpaTransactionManager createTransactionManager(EntityManagerFactory emf) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(emf);
return jpaTransactionManager;
}
}
or it is just about separating responsibilities?
Is it a good practice or something? Is there any difference in comparison to standard #Bean
Both the approaches work as you might have already noticed.
The first approach is similar to inner bean concept.
If you know that the bean is not going to be used by any other bean except the outer bean then you can declare it as an inner bean. The advantage here is that by making the bean as inner bean you are ensuring that it is not exposed to the other beans except the outer bean and so won't be able to use/inject the inner bean in other beans.
Quoting from the above link
An inner bean definition does not require a defined id or name; if specified, the container does not use such a value as an identifier. The container also ignores the scope flag on creation: Inner beans are always anonymous and they are always created with the outer bean. It is not possible to inject inner beans into collaborating beans other than into the enclosing bean or to access them independently.

Spring Boot 1.2.5.RELEASE & Spring Security 4.0.2.RELEASE - How to load configuration file before security context initialization?

I'm facing a problem with Spring: I'm migrating from Spring Security ver. 3.2.7.RELEASE to 4.0.2.RELEASE. Everything was working fine in older version, however a problem occured when it came to loading DataSource.
Let me describe the architecture:
Application is secured with both SAML and LDAP mechanisms (SAML configuration is pretty similar to config given here: https://github.com/vdenotaris/spring-boot-security-saml-sample/blob/master/src/main/java/com/vdenotaris/spring/boot/security/saml/web/config/WebSecurityConfig.java).
They both need to connect to database in order to get some required data. We use MyBatis with Spring Mybatis to get needed data. That's, where the problem begins.
My DAO configuration class looks like this:
#Configuration
#EnableConfigurationProperties
#MapperScan(basePackages = { "pl.myapp" })
public class DaoConfiguration {
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
#Bean
#Primary
public SqlSessionFactoryBean sqlSessionFactoryBean() {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource());
// some stuff happens here
return sqlSessionFactoryBean;
}
#Bean
#Primary
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
#Bean
#ConfigurationProperties(prefix = "liquibase.datasource")
#ConditionalOnProperty(name="liquibase.enabled")
public DataSource liquibaseDataSource() {
DataSource liquiDataSource = DataSourceBuilder.create().build();
return liquiDataSource;
}
}
In previous version it worked like a charm, but now it has a problem loading mappers, resulting in Bean creation exception on FactoryBean type check: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someMapper' defined in file [<filename>]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
over and over again (it's not my problem, it's a known Spring/MyBatis bug).
I did some debugging and discovered something interesting: it looks like DaoConfiguration is not treated like a configuration here! I mean: if I add
#Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
return sqlSessionFactoryBean().getObject();
}
to this config, "normal" call of #Bean annotated method should result in calling proper interceptor, here it lacks this funcionality.
My prediction is that: this config class has not been properly wrapped yet and Spring Security already needs beans produced by it.
Is there any solution to properly load this configuration before Spring Security is initialized? Or am I just wrong and missing something (maybe not so) obvious?

Is there a way to define a default transaction manager in Spring

I have an existing application that uses the Hibernate SessionFactory for one database. We are adding another database for doing analytics. The transactions will never cross so I don't need JTA, but I do want to use JPA EntityManager for the new database.
I've set up the EntityManager and the new transaction manager, which I've qualified, but Spring complains that I need to qualify my existing #Transactional annotations. I'm trying to find a way to tell Spring to use the txManager one as the default. Is there any way of doing this? Otherwise I'll have to add the qualifier to all the existing #Transactional annotations which I would like to avoid if possible.
#Bean(name = "jpaTx")
public PlatformTransactionManager transactionManagerJPA() throws NamingException {
JpaTransactionManager txManager = new JpaTransactionManager(entityManagerFactory());
return txManager;
}
#Bean
public PlatformTransactionManager txManager() throws Exception {
HibernateTransactionManager txManager = new HibernateTransactionManager(sessionFactory());
txManager.setNestedTransactionAllowed(true);
return txManager;
}
Error I'm getting
No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2:
Thanks
I was able to solve this using the #Primary annotation
#Bean(name = "jpaTx")
public PlatformTransactionManager transactionManagerJPA() throws NamingException {
JpaTransactionManager txManager = new JpaTransactionManager(entityManagerFactory());
return txManager;
}
#Bean
#Primary
public PlatformTransactionManager txManager() throws Exception {
HibernateTransactionManager txManager = new HibernateTransactionManager(sessionFactory());
txManager.setNestedTransactionAllowed(true);
return txManager;
}
Since the same type of bean is produced from two methods, you must qualify the #Transactional annotation with the named bean. An easy way around to suite your need will be to use two different Spring application contexts. One operating with the old data source and one operating with new. Each of these contexts will have only one method producing the PlatformTransactionManager instance.

Resources