I am new to Apache Kafka and I am currently working on a small Kafka project. I am working on an example involving Spring Boot and Kafka consumer. However, I am getting an IllegalStateException.
I have a Kafka Configuration class:
package com.example.springbootwithkafkaconsumer.config;
import com.example.springbootwithkafkaconsumer.model.Customer;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
import org.springframework.kafka.core.ConsumerFactory;
import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
import org.springframework.kafka.support.serializer.JsonDeserializer;
import java.util.HashMap;
import java.util.Map;
#KafkaListener
#Configuration
public class KafkaConfiguration {
#Bean
public ConsumerFactory<String, String> consumerFactory() {
Map<String, Object> config = new HashMap<>();
config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
config.put(ConsumerConfig.GROUP_ID_CONFIG, "group_id");
config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
return new DefaultKafkaConsumerFactory<>(config);
}
#Bean
public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
return factory;
}
#Bean
public ConsumerFactory<String, Customer> customerConsumerFactory() {
Map<String, Object> config = new HashMap<>();
config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
config.put(ConsumerConfig.GROUP_ID_CONFIG, "group_json");
config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
return new DefaultKafkaConsumerFactory<>(config, new StringDeserializer(),
new JsonDeserializer<>(Customer.class));
}
#Bean
public ConcurrentKafkaListenerContainerFactory<String, Customer> customerKafkaListenerFactory() {
ConcurrentKafkaListenerContainerFactory<String, Customer> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(customerConsumerFactory());
return factory;
}
}
and a Consumer class:
package com.example.springbootwithkafkaconsumer;
import com.example.springbootwithkafkaconsumer.model.Customer;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.annotation.KafkaListener;
#Configuration
public class Consumer {
#KafkaListener(topics = "Kafka_Example", groupId = "group_id")
public void consumeMessageString(String message) { System.out.println("Consumed String Message: " + message); }
#KafkaListener(topics = "Kafka_Example_Json", groupId = "group_json",
containerFactory = "customerKafkaListenerFactory")
public void consumeMessageJson(Customer customer) { System.out.println("Consumed JSON Message: " + customer); }
}
For some reason, the error message says that a topic must be provided, but I already provided two topics in the Consumer class.
Here is the error message:
java.lang.IllegalStateException: topics, topicPattern, or topicPartitions must be provided
at org.springframework.kafka.listener.AbstractMessageListenerContainer.<init>(AbstractMessageListenerContainer.java:145) ~[spring-kafka-2.8.0.jar:2.8.0]
at org.springframework.kafka.listener.ConcurrentMessageListenerContainer.<init>(ConcurrentMessageListenerContainer.java:81) ~[spring-kafka-2.8.0.jar:2.8.0]
at org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory.createContainerInstance(ConcurrentKafkaListenerContainerFactory.java:75) ~[spring-kafka-2.8.0.jar:2.8.0]
at org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory.createContainerInstance(ConcurrentKafkaListenerContainerFactory.java:46) ~[spring-kafka-2.8.0.jar:2.8.0]
at org.springframework.kafka.config.AbstractKafkaListenerContainerFactory.createListenerContainer(AbstractKafkaListenerContainerFactory.java:377) ~[spring-kafka-2.8.0.jar:2.8.0]
at org.springframework.kafka.config.AbstractKafkaListenerContainerFactory.createListenerContainer(AbstractKafkaListenerContainerFactory.java:69) ~[spring-kafka-2.8.0.jar:2.8.0]
at org.springframework.kafka.config.KafkaListenerEndpointRegistry.createListenerContainer(KafkaListenerEndpointRegistry.java:228) ~[spring-kafka-2.8.0.jar:2.8.0]
at org.springframework.kafka.config.KafkaListenerEndpointRegistry.registerListenerContainer(KafkaListenerEndpointRegistry.java:183) ~[spring-kafka-2.8.0.jar:2.8.0]
at org.springframework.kafka.config.KafkaListenerEndpointRegistry.registerListenerContainer(KafkaListenerEndpointRegistry.java:156) ~[spring-kafka-2.8.0.jar:2.8.0]
at org.springframework.kafka.config.KafkaListenerEndpointRegistrar.registerAllEndpoints(KafkaListenerEndpointRegistrar.java:196) ~[spring-kafka-2.8.0.jar:2.8.0]
at org.springframework.kafka.config.KafkaListenerEndpointRegistrar.afterPropertiesSet(KafkaListenerEndpointRegistrar.java:186) ~[spring-kafka-2.8.0.jar:2.8.0]
at org.springframework.kafka.annotation.KafkaListenerAnnotationBeanPostProcessor.afterSingletonsInstantiated(KafkaListenerAnnotationBeanPostProcessor.java:306) ~[spring-kafka-2.8.0.jar:2.8.0]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:963) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.13.jar:5.3.13]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.13.jar:5.3.13]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.6.1.jar:2.6.1]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[spring-boot-2.6.1.jar:2.6.1]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:412) ~[spring-boot-2.6.1.jar:2.6.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:302) ~[spring-boot-2.6.1.jar:2.6.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[spring-boot-2.6.1.jar:2.6.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290) ~[spring-boot-2.6.1.jar:2.6.1]
at com.example.springbootwithkafkaconsumer.SpringBootWithKafkaConsumerApplication.main(SpringBootWithKafkaConsumerApplication.java:10) ~[classes/:an]
How do I fix this error?
The issue was using the #KafkaListener annotation in the Kafka Configuration class. I replaced it with the #EnableKafka annotation and it fixed the problem.
Related
I have this issue. along 3 days.
When I tried to build the app with maven, i have this isues, but my build was successful, then when I deployed on WebLogic and I call any endpoint this response to me a 500 internal server error.
2021-10-29 17:23:47.788 INFO 64993 --- [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 5.4.32.Final
2021-10-29 17:23:48.021 INFO 64993 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
2021-10-29 17:23:48.269 WARN 64993 --- [ main] o.h.e.j.e.i.JdbcEnvironmentInitiator : HHH000342: Could not obtain connection to query metadata
java.sql.SQLException: No suitable driver found for jdbc/facturador
at java.sql.DriverManager.getConnection(DriverManager.java:689) ~[na:1.8.0_202]
at java.sql.DriverManager.getConnection(DriverManager.java:208) ~[na:1.8.0_202]
at org.springframework.jdbc.datasource.DriverManagerDataSource.getConnectionFromDriverManager(DriverManagerDataSource.java:155) ~[spring-jdbc-5.3.10.jar:5.3.10]
at org.springframework.jdbc.datasource.DriverManagerDataSource.getConnectionFromDriver(DriverManagerDataSource.java:146) ~[spring-jdbc-5.3.10.jar:5.3.10]
at org.springframework.jdbc.datasource.AbstractDriverBasedDataSource.getConnectionFromDriver(AbstractDriverBasedDataSource.java:205) ~[spring-jdbc-5.3.10.jar:5.3.10]
at org.springframework.jdbc.datasource.AbstractDriverBasedDataSource.getConnection(AbstractDriverBasedDataSource.java:169) ~[spring-jdbc-5.3.10.jar:5.3.10]
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:180) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:68) [hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35) [hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:101) [hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263) [hibernate-core-5.4.32.Final.jar:5.4.32.Final] (....)
and
2021-10-29 17:23:48.479 INFO 64993 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2021-10-29 17:23:48.501 INFO 64993 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
2021-10-29 17:23:48.507 WARN 64993 --- [ main] o.h.e.j.e.i.JdbcEnvironmentInitiator : HHH000342: Could not obtain connection to query metadata
java.sql.SQLException: No suitable driver found for jdbc/differenceload
at java.sql.DriverManager.getConnection(DriverManager.java:689) ~[na:1.8.0_202]
at java.sql.DriverManager.getConnection(DriverManager.java:208) ~[na:1.8.0_202]
at org.springframework.jdbc.datasource.DriverManagerDataSource.getConnectionFromDriverManager(DriverManagerDataSource.java:155) ~[spring-jdbc-5.3.10.jar:5.3.10]
at org.springframework.jdbc.datasource.DriverManagerDataSource.getConnectionFromDriver(DriverManagerDataSource.java:146) ~[spring-jdbc-5.3.10.jar:5.3.10]
at org.springframework.jdbc.datasource.AbstractDriverBasedDataSource.getConnectionFromDriver(AbstractDriverBasedDataSource.java:205) ~[spring-jdbc-5.3.10.jar:5.3.10]
at org.springframework.jdbc.datasource.AbstractDriverBasedDataSource.getConnection(AbstractDriverBasedDataSource.java:169) ~[spring-jdbc-5.3.10.jar:5.3.10]
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:180) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:68) [hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35) [hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:101) [hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263) [hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:237) [hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214) [hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.injectServices(DefaultIdentifierGeneratorFactory.java:152) [hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.injectDependencies(AbstractServiceRegistryImpl.java:286) [hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:243) [hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214) [hibernate-core-5.4.32.Final.jar:5.4.32.Final]
There is my DataSourceConfig
import javax.sql.DataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
#Configuration
public class DataSourceConfig {
#Bean(name = "primaryDataSource",destroyMethod = "")
#Primary
#ConfigurationProperties("spring.datasource.primary")
public DataSource firstDataSource(){
return DataSourceBuilder.create().build();
}
#Bean(name = "secondaryDataSource",destroyMethod = "")
#ConfigurationProperties("spring.datasource.secondary")
public DataSource secondDataSource(){
return DataSourceBuilder.create().build();
}
}
Persistence for one DB
import java.util.HashMap;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
#Configuration
#PropertySource("classpath:/application.properties")
#EnableJpaRepositories(basePackages = "com.gt.tigo.diferenceLoad.entities.facturador", entityManagerFactoryRef = "localEntityManager", transactionManagerRef = "localTransactionManager")
public class PersistenceLocalConfig {
#Autowired
private Environment env;
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean localEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(localDataSource());
em.setPackagesToScan(new String[] { "com.gt.tigo.diferenceLoad.entities.local" });
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
em.setJpaPropertyMap(properties);
return em;
}
#Primary
#Bean
public DataSource localDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(env.getProperty("spring.datasource.primary.jndi-name"));
return dataSource;
}
#Primary
#Bean
public PlatformTransactionManager localTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(localEntityManager().getObject());
return transactionManager;
}
}
Persistence for other DB
import java.util.HashMap;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
#Configuration
#PropertySource("classpath:/application.properties")
#EnableJpaRepositories(basePackages = "com.gt.tigo.diferenceLoad.entities.facturador", entityManagerFactoryRef = "FacturadorEntityManager", transactionManagerRef = "facturadorTransactionManager")
public class PersistenceFacturadorConfig {
#Autowired
private Environment env;
#Bean
public LocalContainerEntityManagerFactoryBean FacturadorEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(facturadorDataSource());
em.setPackagesToScan(new String[] { "com.gt.tigo.diferenceLoad.entities.facturador" });
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
em.setJpaPropertyMap(properties);
return em;
}
#Bean
public DataSource facturadorDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(env.getProperty("spring.datasource.secondary.jndi-name"));
return dataSource;
}
#Bean
public PlatformTransactionManager facturadorTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(FacturadorEntityManager().getObject());
return transactionManager;
}
}
Here it's my weblogic JNDI.
webLogic jndi
I tried all things.. but can't solve. please I need some help. Thanks!
#Base de datos LOCAL
spring.datasource.primary.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.primary.jndi-name=jdbc/differenceload
#Base de datos FACTURADOR
spring.datasource.secondary.jndi-name=jdbc/facturador
spring.datasource.secondary.driver-class-name=oracle.jdbc.OracleDriver
Quick look and make some changes in your file.
application.properties
spring.datasource.primary.jndi-name=java:/comp/env/jdbc/SecurityDS
spring.datasource.primary.driver-class-name=org.postgresql.Driver
spring.datasource.secondary.jndi-name=java:/comp/env/jdbc/TmsDS
spring.datasource.secondary.driver-class-name=org.postgresql.Driver
Configuration:
#Configuration
#EnableConfigurationProperties
public class AppConfig {
#Bean #ConfigurationProperties(prefix = "spring.datasource.primary")
public JndiPropertyHolder primary() {
return new JndiPropertyHolder();
}
#Bean #Primary
public DataSource primaryDataSource() {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource(primary().getJndiName());
return dataSource;
}
#Bean# ConfigurationProperties(prefix = "spring.datasource.secondary")
public JndiPropertyHolder secondary() {
return new JndiPropertyHolder();
}
#Bean
public DataSource secondaryDataSource() {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource(secondary().getJndiName());
return dataSource;
}
private static class JndiPropertyHolder {
private String jndiName;
public String getJndiName() {
return jndiName;
}
public void setJndiName(String jndiName) {
this.jndiName = jndiName;
}
}
}
You need to lookup your datasources from jndi instead of creating them using DataSourceBuilder. You can do it like this...
#Configuration
public class WeblogicResourceConfig {
private static final Logger log = LoggerFactory.getLogger(WeblogicResourceConfig.class);
#Autowired
private Environment env;
#Bean
public JndiTemplate jndiTemplate() {
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
return new JndiTemplate(props);
}
// destroyMethod MUST be blank or datasource is removed from jndi tree on
// see https://github.com/spring-projects/spring-framework/issues/17153
#Bean(destroyMethod = "")
#Primary
public DataSource primaryDataSource() throws NamingException {
return (DataSource) jndiTemplate().lookup(env.getProperty("spring.datasource.primary.jndi-name"));
}
// destroyMethod MUST be blank or datasource is removed from jndi tree
// see https://github.com/spring-projects/spring-framework/issues/17153
#Bean(destroyMethod = "")
public DataSource secondaryDataSource() throws NamingException {
return (DataSource) jndiTemplate().lookup(env.getProperty("spring.datasource.secondary.jndi"));
}
}
When creating your LocalContainerEntityManagerFactoryBean inject those datasources above instead of creating new DataSource beans.
I have the following Spring configuration for Kafka:
import org.apache.kafka.clients.producer.ProducerConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.core.ProducerFactory;
import java.util.HashMap;
import java.util.Map;
#Configuration
#RefreshScope
#ConfigurationProperties(prefix = "kafka.status.producer")
public class StatusKafkaProducerConfig {
private String keySerializer;
private String valueSerializer;
private String bootstrapServers;
public void setKeySerializer(String keySerializer) {
this.keySerializer = keySerializer;
}
public void setValueSerializer(String valueSerializer) {
this.valueSerializer = valueSerializer;
}
public void setBootstrapServers(String bootstrapServers) {
this.bootstrapServers = bootstrapServers;
}
#Bean
public Map<String, Object> producerConfigs() {
Map<String, Object> properties = new HashMap<>();
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, keySerializer);
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, valueSerializer);
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
return properties;
}
#Bean
#RefreshScope
public KafkaTemplate<String, String> kafkaTemplate() {
return new KafkaTemplate<>(producerFactory());
}
#Bean
public ProducerFactory<String, String> producerFactory() {
return new DefaultKafkaProducerFactory<>(producerConfigs());
}
}
I migrated the project to latest Spring cloud 2021.0.1 and Spring Boot 2.6.6. But I get the following error stack during boot time:
2022-04-30 19:14:08.350 ERROR 23684 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'producerFactory' defined in class path resource [com/test/StatusUpdateKafkaProducerConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.kafka.core.ProducerFactory]: Factory method 'producerFactory' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:486) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:740) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:415) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[spring-boot-2.6.7.jar:2.6.7]
at com.test.Application.main(Application.java:82) ~[main/:na]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.kafka.core.ProducerFactory]: Factory method 'producerFactory' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-5.3.19.jar:5.3.19]
... 19 common frames omitted
Caused by: java.lang.NullPointerException: null
at java.base/java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1011) ~[na:na]
at java.base/java.util.concurrent.ConcurrentHashMap.putAll(ConcurrentHashMap.java:1089) ~[na:na]
at java.base/java.util.concurrent.ConcurrentHashMap.<init>(ConcurrentHashMap.java:852) ~[na:na]
at org.springframework.kafka.core.DefaultKafkaProducerFactory.<init>(DefaultKafkaProducerFactory.java:205) ~[spring-kafka-2.8.5.jar:2.8.5]
at org.springframework.kafka.core.DefaultKafkaProducerFactory.<init>(DefaultKafkaProducerFactory.java:168) ~[spring-kafka-2.8.5.jar:2.8.5]
at com.test.StatusUpdateKafkaProducerConfig.producerFactory(TransactionStatusUpdateKafkaProducerConfig.java:53) ~[commons-0.0.1-plain.jar:na]
at com.test.StatusUpdateKafkaProducerConfig$$EnhancerBySpringCGLIB$$e907de88.CGLIB$producerFactory$0(<generated>) ~[commons-0.0.1-plain.jar:na]
at com.test.StatusUpdateKafkaProducerConfig$$EnhancerBySpringCGLIB$$e907de88$$FastClassBySpringCGLIB$$db10662a.invoke(<generated>) ~[commons-0.0.1-plain.jar:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.3.19.jar:5.3.19]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) ~[spring-context-5.3.19.jar:5.3.19]
at com.StatusUpdateKafkaProducerConfig$$EnhancerBySpringCGLIB$$e907de88.producerFactory(<generated>) ~[commons-0.0.1-plain.jar:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282) ~[spring-core-5.3.19.jar:5.3.19]
at org.springframework.cloud.context.scope.GenericScope$LockedScopedProxyFactoryBean.invoke(GenericScope.java:485) ~[spring-cloud-context-3.1.2.jar:3.1.2]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.19.jar:5.3.19]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.19.jar:5.3.19]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.19.jar:5.3.19]
at com.StatusUpdateKafkaProducerConfig$$EnhancerBySpringCGLIB$$6800bd04.producerFactory(<generated>) ~[commons-0.0.1-plain.jar:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.19.jar:5.3.19]
... 20 common frames omitted
Do you know how I can fix this issue?
The error stack trace is indicating that a NullPointerException is happening when you are creating a new instance of DefaultKafkaProducerFactory in the producerFactory() method.
Internally, DefaultKafkaProducerFactory creates a ConcurrentHashMap with the provided information to maintain its configuration.
As you can see in the ConcurrentHashMap javadocs, the put method will raise NullPointerException if any of the provided keys or values are null.
As a consequence, probably one of or several of the variables keySerializer, valueSerializer or bootstrapServers are null.
I assume these values are filled by dependency injection according to your #ConfigurationProperties kafka.status.producer. Please, be sure these properties are correctly defined in your Spring configuration.
For testing purposes, try removing the #RefreshScope annotation: it may be a cause of the problem.
The contrary can be a valid solution as well. As indicated in the Spring Cloud documentation when talking about #RefreshScope:
#RefreshScope works (technically) on a #Configuration class,
but it might lead to surprising behavior. For example, it does not
mean that all the #Beans defined in that class are themselves in
#RefreshScope. Specifically, anything that depends on those beans
cannot rely on them being updated when a refresh is initiated, unless
it is itself in #RefreshScope. In that case, it is rebuilt on a
refresh and its dependencies are re-injected. At that point, they are
re-initialized from the refreshed #Configuration).
From that point of view if make perfect sense to annotate with #RefreshScope the producerFactory bean as well. I would try:
import org.apache.kafka.clients.producer.ProducerConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.core.ProducerFactory;
import java.util.HashMap;
import java.util.Map;
#Configuration
#RefreshScope
#ConfigurationProperties(prefix = "kafka.status.producer")
public class StatusKafkaProducerConfig {
private String keySerializer;
private String valueSerializer;
private String bootstrapServers;
public void setKeySerializer(String keySerializer) {
this.keySerializer = keySerializer;
}
public void setValueSerializer(String valueSerializer) {
this.valueSerializer = valueSerializer;
}
public void setBootstrapServers(String bootstrapServers) {
this.bootstrapServers = bootstrapServers;
}
#Bean
#RefreshScope
public Map<String, Object> producerConfigs() {
Map<String, Object> properties = new HashMap<>();
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, keySerializer);
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, valueSerializer);
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
return properties;
}
#Bean
#RefreshScope
public KafkaTemplate<String, String> kafkaTemplate() {
return new KafkaTemplate<>(producerFactory());
}
#Bean
#RefreshScope
public ProducerFactory<String, String> producerFactory() {
return new DefaultKafkaProducerFactory<>(producerConfigs());
}
}
Please, note the inclusion of the additional #RefreshScope annotations.
Finally, consider review the Spring Kafka project documentation, it provides several examples about how to configure your project, whether you are using Spring Boot or not, and gives you further background about DefaultKafkaProducerFactory.
As you can see in the aforementioned docs, if you are using Spring Boot, like in you case, the code can be greatly simplified. Consider review the Spring Boot related documentation about the subject and related properties configuration.
I'm working on a new app (to me) and I received the no bean 'entityManagerFactory' available error on startup. Other people who've had this suggest it would not occur had I properly defined the data source. What confuses me is that either Spring Boot/JPA or Flyway (which I'm also using) insists on specific property names being used for your one data source. I'm not sure how someone would handle it if you had more than one. I need to change our application.properties file to fetch from environment variables so they can fetch the values from a secret. I have one definition so that flyway can do it's possible migrations. I have another so that Spring-Boot can do it's JPA based work. I have another because the existing code previously defined a dataSource and gets wired in accordingly. All are going to the same database. I wish I could use only one collection of application.properties properties, but more importantly, I want this entityManagerFactory error resolved. Because my fixes feel like a kludge, I wanted to reach out and see what I'm not understanding.
Here's the application.properties
spring.profiles.active=sprint-vault-services-not-available
spring.application.name=file-generator
file.generator.schema=FILE_GENERATOR
spring.flyway.enabled=true
spring.flyway.locations=classpath:db/migration
spring.flyway.schemas=${file.generator.schema}
spring.flyway.baseline-on-migrate=false
file-generator.date-format=MMddyy
file-generator.time-format=HHmmss
file-generator.ebcdic-output-path=app/output/ebcdic
file-generator.csv-output-path=app/output/csv
file-generator.header-timestamp-format=yyyyMMddHHmmss
file-generator.file-sequence-number=1
logging.path=app/logs
bcupload_datasource_url=${BCUPLOAD_DATASOURCE_URL}
#spring.jpa.properties.hibernate.default_schema=FILE_GENERATOR
bcupload_datasource_username=${BCUPLOAD_DATASOURCE_USERNAME}
bcupload_datasource_password=${BCUPLOAD_DATASOURCE_PASSWORD}
bcupload_datasource_driver=${BCUPLOAD_DATASOURCE_DRIVER}
bcupload_datasource_flyway_db_name=LocalFileGenerator
spring.datasource.driver-class-name=${BCUPLOAD_DATASOURCE_DRIVER}
spring.datasource.url=${BCUPLOAD_DATASOURCE_URL}
spring.datasource.password=${BCUPLOAD_DATASOURCE_PASSWORD}
spring.datasource.username=${BCUPLOAD_DATASOURCE_USERNAME}
spring.jpa.database-platform=DB2Platform
spring.jpa.show-sql=true
spring.jpa.generate-ddl=false
spring.jpa.hibernate.ddl-auto=none
spring.flyway.url= ${BCUPLOAD_DATASOURCE_URL}
spring.flyway.user=${BCUPLOAD_DATASOURCE_USERNAME}
spring.flyway.password=${BCUPLOAD_DATASOURCE_PASSWORD}
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
2021-04-12 23:06:34 DEBUG o.s.b.d.LoggingFailureAnalysisReporter - Application failed to start due to an exception
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:814)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1282)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:297)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:691)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:508)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:374)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:134)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1699)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1444)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:623)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:611)
at org.springframework.data.repository.config.DeferredRepositoryInitializationListener.onApplicationEvent(DeferredRepositoryInitializationListener.java:51)
at org.springframework.data.repository.config.DeferredRepositoryInitializationListener.onApplicationEvent(DeferredRepositoryInitializationListener.java:36)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:403)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:360)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:897)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:553)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at com.mycompany.cloud.cost.ssc.file.generator.FileGeneratorApplication.main(FileGeneratorApplication.java:22)
Bean definition of datasource:
package com.ibm.cio.cloud.cost.ssc.file.generator.configuration;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
#Configuration
public class DataSourceConfig {
private String dataSourceUrl;
private String userName;
private String password;
private String driver;
/*
#Bean
public EntityManagerFactoryBuilder builder(Environment environment) {
Map<String, String> jpaProperties = new HashMap<>();
jpaProperties.put("hibernate.show_sql", environment.getProperty("spring.jpa.show-sql"));
jpaProperties.put("hibernate.format_sql", environment.getProperty("spring.jpa.properties.hibernate.format_sql"));
jpaProperties.put("hibernate.dialect", environment.getProperty("spring.jpa.properties.hibernate.dialect"));
return new EntityManagerFactoryBuilder(new HibernateJpaVendorAdapter(), jpaProperties, null);
}
*/
#Autowired
public DataSourceConfig(#Value("${bcupload_datasource_url}") String bcupload_datasource_url,
#Value("${bcupload_datasource_username}") String bcupload_datasource_username,
#Value("${bcupload_datasource_password}") String bcupload_datasource_password,
#Value("${bcupload_datasource_driver}") String bcupload_datasource_driver) {
this.dataSourceUrl = bcupload_datasource_url;
this.userName = bcupload_datasource_username;
this.password = bcupload_datasource_password;
this.driver = bcupload_datasource_driver;
}
#Bean(name = "bcUploadDataSource")
public DataSource dataSource() {
return DataSourceBuilder.create()
.url(dataSourceUrl)
.username(userName)
.password(password)
.driverClassName(driver).build();
}
}
I have a project with several datasources and each datasource end up looking something like this:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy;
import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
#Configuration
#EnableJpaRepositories(
basePackages = {"com.your.repositories.packages"},
entityManagerFactoryRef = "entityManagerFactory",
transactionManagerRef = "transactionManager")
public class DataSourceConfig{
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "com.entity.pacakges"});
em.setPersistenceUnitName("your_name");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.hibernate.ddl-auto"));
properties.put("hibernate.dialect", env.getProperty("spring.jpa.properties.hibernate.dialect"));
properties.put("hibernate.show-sql", env.getProperty("spring.jpa.show-sql"));
properties.put("hibernate.temp.use_jdbc_metadata_defaults",
env.getProperty("spring.jpa.use_jdbc_metadata_defaults." + NAME));
properties.put("hibernate.physical_naming_strategy", SpringPhysicalNamingStrategy.class.getName());
properties.put("hibernate.implicit_naming_strategy", SpringImplicitNamingStrategy.class.getName());
em.setJpaPropertyMap(properties);
return em;
}
#Bean(name = "dataSource")
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));
return dataSource;
}
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManager().getObject());
return transactionManager;
}
}
So for your error, probably try to use LocalContainerEntityManagerFactoryBean instead of EntityManagerFactoryBuilder
I am trying to use 2 entity managers in my Spring Batch project in the processor, one for reading and another for persisting data in the db.
The code is as follows
#StepScope
#ComponentScan("com.airtel.billreminder.model")
#Transactional
#Slf4j
public class MyItemProcessor implements ItemProcessor<VoltSiMaster,VoltSiMaster>{
#PersistenceContext(unitName="voltuser")
EntityManager emvoltUser;
#PersistenceContext(unitName="voltreporting")
EntityManager emvoltUserReporting;
#Value("#{jobParameters['notificationNumber']}")
public Long notificationNumber;
#Value("#{jobParameters['dayBeforeNotificationValue']}")
public Long dayBeforeNotificationValue;
#Value("#{jobParameters['firstReminderBeforeDueDate']}")
public Long firstReminderBeforeDueDate;
private ReminderHistory reminderHistory;
#Transactional
#Override
public VoltSiMaster process(VoltSiMaster voltSiMaster) throws Exception {
log.info("Inside Processor");
perpareNotifications(voltSiMaster,notificationNumber,dayBeforeNotificationValue);
return voltSiMaster;
}
#Transactional
private void perpareNotifications(VoltSiMaster siMaster, long notificationNumber,long dayBeforeNotificationValue) {
try {
/*business logic*/
if(notificationNumber>0)
{
txnDone = checkIsTxnAlreadyDone(siMaster);
}
if (!txnDone) {
String[] communincationTypesArray = communincationTypes.split(Pattern.quote("|"));
for (String communincationType : communincationTypesArray) {
log.info("Before sending notification");
if(siMaster.getAmount()>0)
sendNotification(notificationNumber,siMaster,
customerResponse, communincationType);
else
log.info("Amount is "+ siMaster.getBillerName() +" "+siMaster.getAmount()+"so not sending notification");
}
}
else
{
log.info("User has Already Paid Bill so no need to send notification");
}
}
}
private boolean checkIsTxnAlreadyDone(VoltSiMaster siMaster) {
String sqlString = "select * from "+Schemas.VOLT_USER_REPORTING+".volt_txn_log where txn_date_time >= (?1-"+firstReminderBeforeDueDate+") and CUSTOM_COL_3=?2 and uc_id=?3";
try {
Query txnCheckQuery = emvoltUserReporting.createNativeQuery(sqlString, VoltTxnLog.class);
txnCheckQuery.setParameter(1, siMaster.getBillDueDate());
txnCheckQuery.setParameter(2, siMaster.getReference1());
txnCheckQuery.setParameter(3, siMaster.getUcId());
log.info("Query to fire : {} " + txnCheckQuery.toString());
#SuppressWarnings("unchecked")
List<VoltTxnLog> resultList = txnCheckQuery.getResultList();
if (resultList != null) {
if (resultList.size() > 0)
{
for(VoltTxnLog vtxnlog: resultList)
{
if(vtxnlog.getTxnStatus().equals("0") || vtxnlog.getTxnStatus().equals("2"))
return true;
}
}
else
return false;
} else
return false;
} catch (Exception e) {
log.info("Error: "+e.getMessage());
}
return false;
}
#Transactional
private void sendNotification(long notificationNumber,VoltSiMaster siMaster,CusDetResponse customerResponse, String communincationType) {
/*business logic*/
emvoltUser.persist(reminderHistory);
emvoltUser.flush();
}
}
Config file for first entity manager:
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "voltEntityManagerFactory",
transactionManagerRef = "voltTransactionManager", basePackages = {"com.airtel.billreminder.model.voltUser"})
public class VoltUserDbConfig {
#Primary
#Bean(name = "voltDataSource")
#ConfigurationProperties(prefix = "volt.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#PersistenceContext(unitName="voltuser")
#Bean(name = "voltEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean barEntityManagerFactory(
EntityManagerFactoryBuilder builder, #Qualifier("voltDataSource") DataSource dataSource) {
return builder.dataSource(dataSource).packages("com.airtel.billreminder.model.voltUser").persistenceUnit("voltuser")
.build();
}
#Primary
#ConditionalOnMissingBean(name = "transactionManager")
#ConditionalOnBean(DataSource.class)
#Bean(name = "voltTransactionManager")
public PlatformTransactionManager barTransactionManager(
#Qualifier("voltEntityManagerFactory") EntityManagerFactory barEntityManagerFactory) {
return new JpaTransactionManager(barEntityManagerFactory);
}
}
Config file for second entity manager:
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "voltReportingEntityManagerFactory",
transactionManagerRef = "voltReportingTransactionManager", basePackages = {"com.airtel.billreminder.model.voltUserReporting"})
public class VoltUserReportingDbConfig {
#Bean(name = "voltReportingDataSource")
#ConfigurationProperties(prefix = "voltreporting.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#PersistenceContext(unitName="voltreporting")
#Bean(name = "voltReportingEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean barEntityManagerFactory(
EntityManagerFactoryBuilder builder, #Qualifier("voltReportingDataSource") DataSource dataSource) {
return builder.dataSource(dataSource).packages("com.airtel.billreminder.model.voltUserReporting").persistenceUnit("voltreporting")
.build();
}
#ConditionalOnMissingBean(name = "transactionManager")
#ConditionalOnBean(DataSource.class)
#Bean(name = "voltReportingTransactionManager")
public PlatformTransactionManager barTransactionManager(
#Qualifier("voltReportingEntityManagerFactory") EntityManagerFactory barEntityManagerFactory) {
return new JpaTransactionManager(barEntityManagerFactory);
}
}
Spring batch initializes its own transaction manager which i handled using #ConditionalOnMissingBean annotation because it was not creating my custom entity manager previously
Now running this code gives me following exception at emvoltUser.flush() even when i m using #Transactional which should handle the transaction by itself
javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.internal.SessionImpl.checkTransactionNeeded(SessionImpl.java:3505)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1427)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1423)
at sun.reflect.GeneratedMethodAccessor56.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:350)
at com.sun.proxy.$Proxy109.flush(Unknown Source)
at sun.reflect.GeneratedMethodAccessor56.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:305)
at com.sun.proxy.$Proxy109.flush(Unknown Source)
at com.airtel.billreminder.notificationStep.MyItemProcessor.sendNotification(MyItemProcessor.java:233)
at com.airtel.billreminder.notificationStep.MyItemProcessor.perpareNotifications(MyItemProcessor.java:135)
at com.airtel.billreminder.notificationStep.MyItemProcessor.process(MyItemProcessor.java:112)
at com.airtel.billreminder.notificationStep.MyItemProcessor.process(MyItemProcessor.java:58)
at com.airtel.billreminder.notificationStep.MyItemProcessor$$FastClassBySpringCGLIB$$29bbf641.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
at com.airtel.billreminder.notificationStep.MyItemProcessor$$EnhancerBySpringCGLIB$$7ddd0f69.process(<generated>)
at com.airtel.billreminder.notificationStep.MyItemProcessor$$FastClassBySpringCGLIB$$29bbf641.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:136)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
at com.airtel.billreminder.notificationStep.MyItemProcessor$$EnhancerBySpringCGLIB$$ab91a70.process(<generated>)
at org.springframework.batch.core.step.item.SimpleChunkProcessor.doProcess(SimpleChunkProcessor.java:126)
at org.springframework.batch.core.step.item.SimpleChunkProcessor.transform(SimpleChunkProcessor.java:303)
at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:202)
at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:75)
at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406)
at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:330)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:272)
at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:81)
at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375)
at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145)
at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257)
at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:200)
at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:66)
at
org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:67)
at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169)
at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144)
at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:136)
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:308)
at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:141)
at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:134)
at sun.reflect.GeneratedMethodAccessor66.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:197)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:127)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy112.run(Unknown Source)
at com.airtel.billreminder.config.BatchConfig.notificationJobLauncher(BatchConfig.java:343)
at sun.reflect.GeneratedMethodAccessor75.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
I have been stuck at this problem for 2 days now and I searched every possible article or previous answers but none could give me the hint to handle 2 entity managers under single processor pointing to different db connections.
Any help would be appreciated...
You are using #Transactional on your processor which will already be executed in the scope of a transaction driven by Spring Batch. Spring Batch handles the transaction management for you so you don't need to make the processor or writer transactional. I recommend to remove this annotation from your processor and let it participate in the transaction driven by the framework.
The error javax.persistence.TransactionRequiredException: no transaction is in progress means your JpaTransactionManager is not being used. You need to either:
make one of your batch configuration classes extend DefaultBatchConfigurer and override getTransactionManager by returning the JPA transaction manager
or add a bean of type BatchConfigurer in your context and make it return the JpaTransactionManager
Here is an example:
#Bean
public BatchConfigurer batchConfigurer(EntityManagerFactory entityManagerFactory) {
return new DefaultBatchConfigurer() {
#Override
public PlatformTransactionManager getTransactionManager() {
return new JpaTransactionManager(entityManagerFactory);
}
};
}
Note that this requires Spring Batch v4.1+ to work properly.
I have some problem when inherit session factory and configuration from another project :
I have two separate project (core-project, the projects uses core as library)
configuration of my core-project is the following code :
package ir.badnava.pressmining.core.config;
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import ir.badnava.pressmining.core.models.raw.base.BaseRawEntity;
import ir.badnava.pressmining.core.models.raw.page.RawPageEntity;
#Configuration
#ComponentScan(basePackages = { "ir.badnava.pressmining" })
#EnableTransactionManagement
#PropertySource(value = { "classpath:database.properties" })
public class AppConfig {
#Autowired
private Environment environment;
#Bean(name = "sessionFactory")
public LocalSessionFactoryBean getSessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(getDataSource());
setAnotatedClasses(sessionFactory);
sessionFactory.setHibernateProperties(getHibernateProperties());
return sessionFactory;
}
protected void setAnotatedClasses(LocalSessionFactoryBean sessionFactory) {
sessionFactory.setAnnotatedClasses(new Class<?>[]{BaseRawEntity.class, RawPageEntity.class});
}
#Bean(name = "dataSource")
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return dataSource;
}
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("hibernate.hbm2ddl.auto"));
return properties;
}
#Autowired
#Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager(s);
return txManager;
}
}
and the child project configuration is the following code :
package com.badnava.pressmining.web.crawler.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import com.badnava.pressmining.web.crawler.crawler.WebCrawler;
import com.badnava.pressmining.web.crawler.models.speciallist.RepositoryList;
import com.badnava.pressmining.web.crawler.models.speciallist.RepositoryListManager;
import com.badnava.pressmining.web.crawler.models.urlrepo.UrlRepository;
import com.badnava.pressmining.web.crawler.models.urlrepo.UrlRepositoryManager;
#Configuration
public class AppConfig extends ir.badnava.pressmining.core.config.AppConfig{
#Bean
public RepositoryListManager getRepositoryListManager() {
return new RepositoryListManager();
}
#Bean
public UrlRepositoryManager getUrlRepositoryManager() {
return new UrlRepositoryManager();
}
#Bean
public WebCrawler getWebCrawler(){
return new WebCrawler();
}
#Override
protected void setAnotatedClasses(LocalSessionFactoryBean sessionFactory) {
super.setAnotatedClasses(sessionFactory);
sessionFactory.setAnnotatedClasses(new Class<?>[]{RepositoryList.class, UrlRepository.class});
}
}
and my problem is that in the child project I overload the setAnnotatedClass method and calling it's super and give the session factory my entities class but after doing something like save or update session factory says that unknown mapping entity
I have no idea about what did I wrong in these code because I did that before with XML file configuration
Update :
log :
Exception in thread "Thread-3" org.hibernate.MappingException: Unknown entity: ir.badnava.pressmining.core.models.raw.page.RawPageEntity
at org.hibernate.internal.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:776)
at org.hibernate.internal.SessionImpl.getEntityPersister(SessionImpl.java:1533)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:104)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:682)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:674)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:669)
at ir.badnava.pressmining.core.models.raw.base.BaseDao.save(BaseDao.java:16)
at ir.badnava.pressmining.core.models.raw.base.BaseDao$$FastClassBySpringCGLIB$$d95ff2ca.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:280)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
at ir.badnava.pressmining.core.models.raw.base.BaseDao$$EnhancerBySpringCGLIB$$95dae3fd.save(<generated>)
at ir.badnava.pressmining.core.models.raw.base.BaseManager.save(BaseManager.java:23)
at com.badnava.pressmining.web.crawler.crawler.WebCrawler$3.run(WebCrawler.java:142)
at java.lang.Thread.run(Thread.java:745)
Problem solved :
the problem was that the setAnnotatedClasses method is a setter method and I changed my code to bellow code and that's work
#Override
protected Class<?>[] setAnotatedClasses() {
Class<?>[] superClasses = super.setAnotatedClasses(sessionFactory);
Class<?>[] childClasses = new Class<?>[]{RepositoryList.class, UrlRepository.class};
Class<?>[] allClasses = new Class<?>[childClasses.length + superClasses.length];
for (int i = 0; i < allClasses.length; i++) {
if (i < superClasses.length)
allClasses[i] = superClasses[i];
else
allClasses[i] = childClasses[i-childClasses.length];
}
return allClasses;
}
thanks to #sura2k