I try to setup a project with spring-test using TestNg in Maven. The code is like:
#ContextConfiguration(classes={WebMvcTestConfig.class})
public class MyResourceParserTest extends AbstractTestNGSpringContextTests {
#BeforeMethod
public void setup() throws Exception {
}
A WebMvcTestConfig class simply defined a bean:
#Configuration
#ComponentScan(basePackages={"com.test.myapp.model"})
#EnableTransactionManagement
public class WebMvcTestConfig {
private static final String relativeConfigURI = "\\MyAppSpringConfig\\";
private static final String userHomeURI = System.getProperty("user.home");
private static final String jdbcPropertiesFileName = "jdbc.properties";
private static final String hibernatePropertiesFileName = "hibernate.properties";
#Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertySourcesPlaceholderConfigurer.setLocation(new FileSystemResource(userHomeURI + relativeConfigURI + jdbcPropertiesFileName));
return propertySourcesPlaceholderConfigurer;
}
#Bean
public DataSource dataSource(
#Value("${jdbc.driverClassName}") String driverClass,
#Value("${jdbc.url}") String jdbcUrl,
#Value("${jdbc.username}") String username,
#Value("${jdbc.password}") String password) {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(jdbcUrl);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
#Bean
public LocalSessionFactoryBean localSessionFactoryBean() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource("", "", "", ""));
sessionFactory.setPackagesToScan("com.test.myapp.model.domain");
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public Properties hibernateProperties() {
Properties hibernateProperties = new Properties();
try {
hibernateProperties.load(new FileInputStream(userHomeURI + relativeConfigURI + hibernatePropertiesFileName));
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
return hibernateProperties;
}
#Bean
public PlatformTransactionManager platformTransactionManager() {
return new HibernateTransactionManager(localSessionFactoryBean().getObject());
}
}
I got error for Failed to load ApplicationContext when running mvn test from command line:
java.lang.IllegalStateException: Failed to load ApplicationContext
Can you help me?
3 things I notice from your configuration.
Your loading of configuration files is strange, use Spring for that instead of rolling your own. Simply use #PropertySource for that.
The propertySourcesPlaceholderConfigurer() must be static
Your call to datasource will lead to an invalid datasource configuration.
Try the following configuration class.
#Configuration
#ComponentScan(basePackages={"com.test.myapp.model"})
#EnableTransactionManagement
#PropertySource({"${user.home}/MyAppSpringConfig/jdbc.properties","${user.home}/MyAppSpringConfig/hibernate.properties"}
public class WebMvcTestConfig {
#Autowired
private Environment env;
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new new PropertySourcesPlaceholderConfigurer();
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getRequiredProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("env.username", ""));
dataSource.setPassword(env.getProperty("env.password", ""));
return dataSource;
}
#Bean
public LocalSessionFactoryBean localSessionFactoryBean() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan("com.test.myapp.model.domain");
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public Properties hibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
// Other properties
return hibernateProperties;
}
#Bean
public PlatformTransactionManager platformTransactionManager() {
return new HibernateTransactionManager(localSessionFactoryBean().getObject());
}
}
Related
I have implemented the application using Spring RoutingDataSource.
Spring -> DS1,
DS2
Based on the logged in URL I am changing the Data Source. it is working fine.
Coming to the quartz, I am unable to change the data source dynamically. Always jobs are getting scheduled on default data source.
#Configuration
public class SchedulerConfig {
#Autowired
private DataSource dataSource;
#Autowired
private QuartzProperties quartzProperties;
#Bean
public JobFactory jobFactory(ApplicationContext applicationContext) {
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
#Bean
public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) {
Properties properties = new Properties();
properties.putAll(quartzProperties.getProperties());
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setJobFactory(jobFactory);
factory.setDataSource(dataSource);
factory.setGlobalJobListeners(jobListener());
factory.setQuartzProperties(properties);
return factory;
}
#Bean
public JobListenerSupport jobListener() {
return new JobListener();
}
}
Data Source Routing Configuration::
#Component
public class DataSourceRouting extends AbstractRoutingDataSource {
private DataSourceOneConfig dataSourceOneConfig;
private DataSourceTwoConfig dataSourceTwoConfig;
private DataSourceContextHolder dataSourceContextHolder;
public DataSourceRouting(DataSourceContextHolder dataSourceContextHolder, DataSourceOneConfig dataSourceOneConfig,
DataSourceTwoConfig dataSourceTwoConfig) {
this.dataSourceOneConfig = dataSourceOneConfig;
this.dataSourceTwoConfig = dataSourceTwoConfig;
this.dataSourceContextHolder = dataSourceContextHolder;
Map<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put(DataSourceEnum.tenant1, dataSourceOneDataSource());
dataSourceMap.put(DataSourceEnum.tenant2, dataSourceTwoDataSource());
this.setTargetDataSources(dataSourceMap);
this.setDefaultTargetDataSource(dataSourceTwoDataSource());
}
#Override
protected Object determineCurrentLookupKey() {
return dataSourceContextHolder.getBranchContext();
}
public DataSource dataSourceOneDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(dataSourceOneConfig.getUrl());
dataSource.setUsername(dataSourceOneConfig.getUsername());
dataSource.setPassword(dataSourceOneConfig.getPassword());
return dataSource;
}
public DataSource dataSourceTwoDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(dataSourceTwoConfig.getUrl());
dataSource.setUsername(dataSourceTwoConfig.getUsername());
dataSource.setPassword(dataSourceTwoConfig.getPassword());
return dataSource;
}
}
Data Soruce Config ::
#RequiredArgsConstructor
#DependsOn("dataSourceRouting")
public class DataSourceConfig {
private final DataSourceRouting dataSourceRouting;
#Bean
#Primary
public DataSource dataSource() {
return dataSourceRouting;
}
#Bean(name = "entityManager")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
return builder.dataSource(dataSource()).packages("com.model.entity").build();
}
#Bean(name = "transcationManager")
public JpaTransactionManager transactionManager(
#Autowired #Qualifier("entityManager") LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
return new JpaTransactionManager(entityManagerFactoryBean.getObject());
}
}
I'm trying to implement the OpenSessionInView pattern (antipattern) with Spring 5. I configured via Java (not xml) the OpenSessionInView in my WebMvcConfigurer, and watching the logs it seems that is already running. But when I try to load a lazy collection it says the known "Could not write JSON: failed to lazily initialize a collection of role:..."
The crazy stuff is that I see in my logs:
DEBUG [http-nio-8080-exec-7] (OpenSessionInViewInterceptor.java:128) - Opening Hibernate Session in OpenSessionInViewInterceptor
DEBUG [http-nio-8080-exec-7] (AbstractPlatformTransactionManager.java:370) - Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findById]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
DEBUG [http-nio-8080-exec-7] (JpaTransactionManager.java:393) - Opened new EntityManager [SessionImpl(1867707287<open>)] for JPA transaction
DEBUG [http-nio-8080-exec-7] (DriverManagerDataSource.java:144) - Creating new JDBC DriverManager Connection to [jdbc:mysql://MYIP:3306/DB_NAME?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Europe/Madrid]
DEBUG [http-nio-8080-exec-7] (DataSourceUtils.java:186) - Setting JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl#2e6ff9ac] read-only
DEBUG [http-nio-8080-exec-7] (TransactionImpl.java:56) - On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == false
...
...
...
WARN [http-nio-8080-exec-7] (AbstractHandlerExceptionResolver.java:199) - Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: com....Route.styles, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role...
DEBUG [http-nio-8080-exec-7] (OpenSessionInViewInterceptor.java:153) - Closing Hibernate Session in OpenSessionInViewInterceptor
So, it seems that the session is opened as it should, is not closed when the exception is thrown. But my EntityManager is not using that session... Am I correct? How can I achieve that?
Thanks!
EDIT:
My WebConfig.java:
#Configuration
#ComponentScan
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
#Value( "${resources.files.location}" )
private String fileLocation;
#Autowired
DataSource datasource;
#Autowired
private Environment env;
#Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("Messages");
messageSource.setCacheMillis(10);
return messageSource;
}
#Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(Locale.getDefault());
return localeResolver;
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeInterceptor = new LocaleChangeInterceptor();
localeInterceptor.setIgnoreInvalidLocale(true);
localeInterceptor.setParamName("idioma");
return localeInterceptor;
}
#Bean
public PlatformTransactionManager hibernateTransactionManager() {
HibernateTransactionManager transactionManager
= new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactoryBean().getObject());
return transactionManager;
}
#Bean
public ViewResolver internalResourceViewResolver() {
InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
internalResourceViewResolver.setPrefix("/WEB-INF/views/");
internalResourceViewResolver.setSuffix(".jsp");
return internalResourceViewResolver;
}
public void addInterceptors(InterceptorRegistry registry) {
OpenSessionInViewInterceptor openSessionInViewInterceptor = new OpenSessionInViewInterceptor();
openSessionInViewInterceptor.setSessionFactory(sessionFactoryBean().getObject());
registry.addWebRequestInterceptor(openSessionInViewInterceptor).addPathPatterns("/**");
registry.addInterceptor(new miLoggerInterceptor());
registry.addInterceptor(localeChangeInterceptor());
}
#Bean
public FilterRegistrationBean openEntityManagerInViewFilter() {
FilterRegistrationBean reg = new FilterRegistrationBean();
reg.setName("OpenEntityManagerInViewFilter");
reg.setFilter(new OpenEntityManagerInViewFilter());
return reg;
}
#Bean
public LocalSessionFactoryBean sessionFactoryBean() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(datasource);
sessionFactory.setPackagesToScan("my.package");
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
private Properties hibernateProperties() {
Properties jpaProperties = new Properties();
jpaProperties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
jpaProperties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
jpaProperties.put("hibernate.format_sql", env.getProperty("hibernate.format_sql"));
return jpaProperties;
}
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/img/**").addResourceLocations("/img/");
registry.addResourceHandler("/.well-known/acme-challenge/**").addResourceLocations("/.well-known/acme-challenge/");
registry.addResourceHandler("/webfonts/**").addResourceLocations("/webfonts/");
registry.addResourceHandler("/multimedia/").addResourceLocations("file:"+fileLocation);
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
registry.addResourceHandler("/files/**").addResourceLocations("file:///C:/tmp/images/");
registry.addResourceHandler("/favico.ico").addResourceLocations("/favico.ico");
}
}
BusinessConfig.java:
#Configuration
#ComponentScan
#PropertySources({
#PropertySource("classpath:application.properties"),
})
#EnableJpaRepositories("com.muskers.web.business.repositories")
public class BusinessConfig {
#Autowired
private Environment env;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("db.driver"));
dataSource.setUrl(env.getProperty("db.url"));
dataSource.setUsername(env.getProperty("db.username"));
dataSource.setPassword(env.getProperty("db.password"));
return dataSource;
}
#Bean
public PasswordEncoder delegatingPasswordEncoder() {
PasswordEncoder defaultEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put("bcrypt", new BCryptPasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
DelegatingPasswordEncoder passwordEncoder = new DelegatingPasswordEncoder(
"bcrypt", encoders);
passwordEncoder.setDefaultPasswordEncoderForMatches(defaultEncoder);
return passwordEncoder;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource());
emf.setPackagesToScan(User.class.getPackage().getName());
HibernateJpaVendorAdapter hibernateJpa = new HibernateJpaVendorAdapter();
hibernateJpa.setDatabase(Database.MYSQL);
hibernateJpa.setDatabasePlatform(env.getProperty("hibernate.dialect"));
hibernateJpa.setGenerateDdl(env.getProperty("hibernate.generateDdl", Boolean.class));
hibernateJpa.setShowSql(env.getProperty("hibernate.show_sql", Boolean.class));
emf.setJpaVendorAdapter(hibernateJpa);
Properties jpaProperties = new Properties();
jpaProperties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
jpaProperties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
jpaProperties.put("hibernate.format_sql", env.getProperty("hibernate.format_sql"));
emf.setJpaProperties(jpaProperties);
return emf;
}
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager txnMgr = new JpaTransactionManager();
txnMgr.setEntityManagerFactory(entityManagerFactory().getObject());
return txnMgr;
}
#PostConstruct
public void setTimeZone() {
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Madrid"));
}
public class Roles {
public final static String ROLE_USER = "USER";
public final static String ROLE_ADMIN = "ADMIN";
}
public class Authorities {
public final static String MANAGE_GYMS = "MANAGE_GYMS";
public final static String MANAGE_USERS = "MANAGE_USERS";
public final static String READ_GYMS = "READ_GYMS";
public final static String CREATE_GYMS = "CREATE_GYMS";
public final static String CREATE_ROUTES = "CREATE_ROUTES";
public final static String READ_ROUTES = "READ_ROUTES";
public final static String MANAGE_ROUTES = "MANAGE_ROUTES";
}
}
App.java:
public class App extends AbstractAnnotationConfigDispatcherServletInitializer
{
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { BusinessConfig.class, WebSecurityConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
return new Filter[] { characterEncodingFilter};
}
}
What we are doing: Update subscription for received business ID.
We receive business ID on activeMQ queue.
JMSListener picked business ID, find the all associated subscription for received business.
Process all subscription identify who need update (can be zero or more than one).
For each subscription we call service method udate(SubscriptionDTO subscriptionDTO). Find the subscription entity object. This update method update the entity object using dto object. Then we call flush method on it. Note : Update method is annotated with #transactional. Call flush method from service#udpate(dto) method.
We observed different behavior in windows vs Linux. On windows it worked well but on Linux we are getting failure after execution of flush method– javax.persistence.TransactionRequiredException: no transaction is in progress
We tried adding #Transactional on JMSListner but got same error on Linux. But when we tried without call of flush method error gone but no update happened. Subscription data is same as before.
Not sure how good problem was explained above.
Looking for guidance, much appreciated for response.
JPA Configuration
package edu.learn.config;
#Configuration
#EnableJpaRepositories(basePackages = "edu.learn.repositories", entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "transactionManager")
#EnableTransactionManagement
public class JpaConfiguration
{
private final String DEFAULT_TEST_QUERY = "SELECT 1";
#Autowired
private Environment environment;
#Value("${datasource.maxPoolSize:10}")
private int maxPoolSize;
/*
* Populate SpringBoot DataSourceProperties object directly from
* application.yml based on prefix.Thanks to .yml, Hierachical data is
* mapped out of the box with matching-name properties of
* DataSourceProperties object].
*/
#Bean
#Primary
#ConfigurationProperties(prefix = "datasource")
public DataSourceProperties dataSourceProperties()
{
return new DataSourceProperties();
}
/*
* Configure HikariCP pooled DataSource.
*/
#Bean
public DataSource dataSource()
{
DataSourceProperties dataSourceProperties = dataSourceProperties();
HikariDataSource dataSource = (HikariDataSource) DataSourceBuilder.create()
.type(com.zaxxer.hikari.HikariDataSource.class).username(dataSourceProperties.getUsername())
.password(dataSourceProperties.getPassword()).build();
dataSource.setMaximumPoolSize(PropertyUtil.getMaxPoolSize(environment));
dataSource.setInitializationFailFast(PropertyUtil.getInitializationFailFast(environment));
dataSource.setMinimumIdle(PropertyUtil.getMinIdle(environment));
dataSource.setConnectionTestQuery(DEFAULT_TEST_QUERY);
dataSource.setConnectionTimeout(PropertyUtil.getConnectionTimeout(environment));
dataSource.setIdleTimeout(PropertyUtil.getIdleTimeout(environment));
dataSource.setMaxLifetime(PropertyUtil.getMaxLifetime(environment));
dataSource.setDataSourceClassName(PropertyUtil.getDataSourceClassName(environment));
if ("com.mysql.jdbc.jdbc2.optional.MysqlDataSource".equals(PropertyUtil.getDataSourceClassName(environment)))
{
dataSource.addDataSourceProperty("databaseName", PropertyUtil.defaultSchema(environment));
dataSource.addDataSourceProperty("cachePrepStmts", PropertyUtil.getCachePrepStmts(environment));
dataSource.addDataSourceProperty("prepStmtCacheSize", PropertyUtil.getPrepStmtCacheSize(environment));
dataSource.addDataSourceProperty(
"prepStmtCacheSqlLimit", PropertyUtil.getPrepStmtCacheSqlLimit(environment)
);
dataSource.addDataSourceProperty("useServerPrepStmts", PropertyUtil.getUseServerPrepStmts(environment));
dataSource.addDataSourceProperty("serverName", PropertyUtil.dbServerName(environment));
dataSource.addDataSourceProperty("portNumber", PropertyUtil.portNumber(environment));
}
return dataSource;
}
/*
* Entity Manager Factory setup.
*/
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException
{
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan(new String[]
{
"edu.learn.model"
});
factoryBean.setJpaVendorAdapter(jpaVendorAdapter());
factoryBean.setJpaProperties(jpaProperties());
return factoryBean;
}
/*
* Provider specific adapter.
*/
#Bean
public JpaVendorAdapter jpaVendorAdapter()
{
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
return hibernateJpaVendorAdapter;
}
/*
* Here you can specify any provider specific properties.
*/
private Properties jpaProperties()
{
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.put("hibernate.globally_quoted_identifiers", "true");
properties.put("hibernate.hbm2ddl.auto", "validates");
properties.put("ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
properties.put("show_sql", "false");
properties.put("format_sql", "true");
return properties;
}
#Bean
#Autowired
public PlatformTransactionManager transactionManager(EntityManagerFactory emf)
{
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(emf);
return txManager;
}
static class PropertyUtil
{
final static String DEFAULT_CHARACTER_ENCODING = "utf-8";
final static String DEFAULT_DATASOURCE_CLASS = "com.mysql.jdbc.Driver";
public static boolean getCachePrepStmts(final Environment environment)
{
String cachePrepStmts = environment.getProperty("spring.datasource.hikari.cachePrepStmts");
if ("false".equalsIgnoreCase(cachePrepStmts))
{
return false;
}
return true;
}
public static int getPrepStmtCacheSize(final Environment environment)
{
String prepStmtCacheSize = environment.getProperty("spring.datasource.hikari.prepStmtCacheSize");
try
{
return Integer.parseInt(prepStmtCacheSize);
}
catch(Exception e)
{
return 250;
}
}
public static int getPrepStmtCacheSqlLimit(final Environment environment)
{
String prepStmtCacheSqlLimit = environment.getProperty("spring.datasource.hikari.prepStmtCacheSqlLimit");
try
{
return Integer.parseInt(prepStmtCacheSqlLimit);
}
catch(Exception e)
{
return 2048;
}
}
public static boolean getUseServerPrepStmts(final Environment environment)
{
String useServerPrepStmts = environment.getProperty("spring.datasource.hikari.useServerPrepStmts");
if ("false".equalsIgnoreCase(useServerPrepStmts))
{
return false;
}
return true;
}
public static boolean getInitializationFailFast(final Environment environment)
{
String initializationFailFast = environment.getProperty("spring.datasource.hikari.initializationFailFast");
if ("false".equalsIgnoreCase(initializationFailFast))
{
return false;
}
return true;
}
public static long getConnectionTimeout(final Environment environment)
{
String connectionTimeout = environment.getProperty("spring.datasource.hikari.connectionTimeout");
try
{
return Integer.parseInt(connectionTimeout);
}
catch(Exception e)
{
return TimeUnit.SECONDS.toMillis(60);
}
}
public static long getIdleTimeout(final Environment environment)
{
String idleTimeout = environment.getProperty("spring.datasource.hikari.idleTimeout");
try
{
return Integer.parseInt(idleTimeout);
}
catch(Exception e)
{
return TimeUnit.SECONDS.toMillis(60);
}
}
public static long getMaxLifetime(final Environment environment)
{
String maxLifetime = environment.getProperty("spring.datasource.hikari.maxLifetime");
try
{
return Integer.parseInt(maxLifetime);
}
catch(Exception e)
{
return TimeUnit.SECONDS.toMillis(90);
}
}
public static int getMinIdle(final Environment environment)
{
String minIdle = environment.getProperty("spring.datasource.hikari.minIdle");
try
{
return Integer.parseInt(minIdle);
}
catch(Exception e)
{
return 5;
}
}
public static int getMaxPoolSize(final Environment environment)
{
String maxPoolSize = environment.getProperty("spring.datasource.maxPoolSize");
try
{
return Integer.parseInt(maxPoolSize);
}
catch(Exception e)
{
return 25;
}
}
public static String getDataSourceClassName(final Environment environment)
{
String dataSourceClassName = environment.getProperty("spring.datasource.dataSourceClassName");
if (dataSourceClassName != null && "".equalsIgnoreCase(dataSourceClassName.trim()) == false)
{
return dataSourceClassName;
}
return DEFAULT_DATASOURCE_CLASS;
}
public static String getCharacterEncoding(final Environment environment)
{
String characterEncoding = environment.getProperty("spring.datasource.characterEncoding");
if (characterEncoding != null && "".equalsIgnoreCase(characterEncoding.trim()) == false)
{
return characterEncoding;
}
return DEFAULT_CHARACTER_ENCODING;
}
public static boolean getUniCode(final Environment environment)
{
String useUnicode = environment.getProperty("spring.datasource.useUnicode");
if ("false".equalsIgnoreCase(useUnicode))
{
return false;
}
return true;
}
public static String showSQL(final Environment environment)
{
String showSQL = environment.getProperty("spring.datasource.hibernate.showSQL");
if ("false".equalsIgnoreCase(showSQL))
{
return "false";
}
return "true";
}
public static String formatSQL(final Environment environment)
{
String formatSQL = environment.getProperty("spring.datasource.hibernate.format_sql");
if ("false".equalsIgnoreCase(formatSQL))
{
return "false";
}
return "true";
}
public static String dbServerName(final Environment environment)
{
String dbServerName = environment.getProperty("spring.datasource.serverName");
if (dbServerName == null || "".equalsIgnoreCase(dbServerName.trim()))
{
return "localhost";
}
return dbServerName;
}
public static int portNumber(final Environment environment)
{
String portNumber = environment.getProperty("spring.datasource.portNumber");
try
{
return Integer.parseInt(portNumber);
}
catch(Exception e)
{
return 3306;
}
}
public static String defaultSchema(final Environment environment)
{
String defaultSchema = environment.getProperty("spring.datasource.defaultSchema");
if (defaultSchema == null || "".equalsIgnoreCase(defaultSchema.trim()))
{
return "subscription";
}
return defaultSchema;
}
}
}
JMS Configuration
#EnableJms
#Configuration
public class JmsConfiguration
{
#Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer)
{
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
configurer.configure(factory, connectionFactory);
return factory;
}
}
Startup class
#Import({JpaConfiguration.class, JmsConfiguration.class})
#SpringBootApplication(scanBasePackages={"edu.learn"})
public class SubscriptionApiApplication
{
public static void main(String[] args)
{
SpringApplication.run(SubscriptionApiApplication.class, args);
}
}
JMS queue listener
#Component
public class OrderTransactionReceiver
{
private static final Logger LOGGER = LoggerFactory.getLogger(OrderTransactionReceiver.class);
#Autowired
private SubscriptionService subsriptionService;
#JmsListener(destination = "OrderTransactionQueue", containerFactory = "myFactory")
public void receiveMessage(String businessID)
{
List<SubscriptionDTO> subscriptions = subsriptionService.findByBusinessID(businessID);
for (SubscriptionDTO subscription : subscriptions)
{
subscription.setStatus("active");
subsriptionService.update(subscription);
}
}
}
Service
#Service
class RepositorySubscriptionService implements SubscriptionService
{
private static final Logger LOGGER = LoggerFactory.getLogger(RepositorySubscriptionService.class);
private final SubscriptionRepository repository;
#Transactional
#Override
public SubscriptionDTO update(SubscriptionDTO updatedSubscriptionEntry)
{
LOGGER.info(
"Updating the information of a subscription entry by using information: {}", updatedSubscriptionEntry
);
SubscriptionEntity updated = findSubscriptionEntryById(updatedSubscriptionEntry.getId());
updated.update(updatedSubscriptionEntry.getStatus());
// We need to flush the changes or otherwise the returned object
// doesn't contain the updated audit information.
repository.flush();
LOGGER.info("Updated the information of the subscription entry: {}", updated);
return SubscriptionMapper.mapEntityIntoDTO(updated);
}
}
Repostiory
public interface SubscriptionRepository extends
Repository<SubscriptionEntity, String>,
JpaSpecificationExecutor<SubscriptionEntity>
{
void delete(SubscriptionEntity deleted);
List<SubscriptionEntity> findAll();
Optional<SubscriptionEntity> findOne(String id);
List<SubscriptionEntity> findByBusinessID(final String businessID);
void flush();
SubscriptionEntity save(SubscriptionEntity persisted);
}
JTA transaction configuration
#Configuration
#EnableJpaRepositories(basePackages = "edu.learn.repositories", entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "transactionManager")
#EnableTransactionManagement
public class JpaConfiguration
{
private final String DEFAULT_TEST_QUERY = "SELECT 1";
#Autowired
private Environment environment;
#Value("${datasource.maxPoolSize:10}")
private int maxPoolSize;
/*
* Populate SpringBoot DataSourceProperties object directly from
* application.yml based on prefix.Thanks to .yml, Hierachical data is
* mapped out of the box with matching-name properties of
* DataSourceProperties object].
*/
#Bean
#Primary
#ConfigurationProperties(prefix = "datasource")
public DataSourceProperties dataSourceProperties()
{
return new DataSourceProperties();
}
/*
* Configure HikariCP pooled DataSource.
*/
#Bean(initMethod = "init", destroyMethod = "close")
public DataSource dataSource()
{
DataSourceProperties dataSourceProperties = dataSourceProperties();
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setServerName(PropertyUtil.dbServerName(environment));
mysqlXaDataSource.setPort(PropertyUtil.portNumber(environment));
mysqlXaDataSource.setUser(dataSourceProperties.getUsername());
mysqlXaDataSource.setPassword(dataSourceProperties.getPassword());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setDatabaseName(PropertyUtil.defaultSchema(environment));
mysqlXaDataSource.setCachePreparedStatements(PropertyUtil.getCachePrepStmts(environment));
try
{
mysqlXaDataSource.setPrepStmtCacheSqlLimit(PropertyUtil.getPrepStmtCacheSqlLimit(environment));
mysqlXaDataSource.setPrepStmtCacheSize(PropertyUtil.getPrepStmtCacheSize(environment));
}
catch (SQLException e)
{
e.printStackTrace();
}
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("xaSubscription");
xaDataSource.setTestQuery(DEFAULT_TEST_QUERY);
xaDataSource.setMaxPoolSize(PropertyUtil.getMaxPoolSize(environment));
xaDataSource.setMaxIdleTime(PropertyUtil.getMinIdle(environment));
xaDataSource.setMaxLifetime((int)PropertyUtil.getMaxLifetime(environment));
xaDataSource.setBorrowConnectionTimeout((int)PropertyUtil.getConnectionTimeout(environment));
return xaDataSource;
}
/*
* Entity Manager Factory setup.
*/
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException
{
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan(new String[]
{
"edu.learn.model"
});
factoryBean.setJpaVendorAdapter(jpaVendorAdapter());
factoryBean.setJpaProperties(jpaProperties());
return factoryBean;
}
/*
* Provider specific adapter.
*/
#Bean
public JpaVendorAdapter jpaVendorAdapter()
{
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
return hibernateJpaVendorAdapter;
}
/*
* Here you can specify any provider specific properties.
*/
private Properties jpaProperties()
{
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.put("hibernate.globally_quoted_identifiers", "true");
properties.put("hibernate.hbm2ddl.auto", "validates");
properties.put("ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
properties.put("show_sql", "false");
properties.put("format_sql", "true");
properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
properties.put("javax.persistence.transactionType", "JTA");
return properties;
}
#Bean
public UserTransaction userTransaction() throws Throwable
{
UserTransactionImp userTransactionImp = new UserTransactionImp();
userTransactionImp.setTransactionTimeout(1000);
return userTransactionImp;
}
#Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
public TransactionManager atomikosTransactionManager() throws Throwable
{
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(false);
AtomikosJtaPlatform.transactionManager = userTransactionManager;
return userTransactionManager;
}
#Bean(name = "transactionManager")
#DependsOn({ "userTransaction", "atomikosTransactionManager" })
public PlatformTransactionManager transactionManager() throws Throwable
{
UserTransaction userTransaction = userTransaction();
AtomikosJtaPlatform.transaction = userTransaction;
TransactionManager atomikosTransactionManager = atomikosTransactionManager();
return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
}
}
public class AtomikosJtaPlatform extends AbstractJtaPlatform
{
private static final long serialVersionUID = 1L;
static TransactionManager transactionManager;
static UserTransaction transaction;
#Override
protected TransactionManager locateTransactionManager()
{
return transactionManager;
}
#Override
protected UserTransaction locateUserTransaction()
{
return transaction;
}
}
I use spring version 5.0.1, hibernate version 5.2.12.
When I call getHibernateTemplate (), I get null
what am I doing wrong?
Dao confif:
#PropertySource(value = {"classpath:hibernate.properties"})
#ComponentScan("ru.bochkarev.hmcs.dao")
#EnableTransactionManagement
#Configuration
public class DaoConfig {
#Autowired
private Environment environment;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("hibernate.connection.driver_class"));
dataSource.setUrl(environment.getRequiredProperty("hibernate.connection.url"));
dataSource.setUsername(environment.getRequiredProperty("hibernate.connection.username"));
dataSource.setPassword(environment.getRequiredProperty("hibernate.connection.password"));
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
return properties;
}
#Bean
public SessionFactory sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan("ru.bochkarev.hmcs.model");
sessionFactory.setHibernateProperties(hibernateProperties());
try {
sessionFactory.afterPropertiesSet();
} catch (IOException e) {
e.printStackTrace();
}
return sessionFactory.getObject();
}
#Bean
public HibernateTransactionManager hibernateTransactionManager(){
return new HibernateTransactionManager(sessionFactory());
}
#Bean
public HibernateTemplate hibernateTemplate() {
return new HibernateTemplate(sessionFactory());
}
}
.................................................................
Implement dao:
#Transactional
#Repository
public class DaoTest extends HibernateDaoSupport {
public void save(TestModel testModel) {
getHibernateTemplate().saveOrUpdate(testModel);
}
}
When I call getHibernateTemplate (), I get null
Try below code for your DAO class and let us know if it works.
#Transactional
#Repository
public class DaoTest {
#Autowired
private HibernateTemplate hibernateTemplate;
public void save(TestModel testModel) {
getHibernateTemplate().saveOrUpdate(testModel);
}
}
I have a JavaConfig configurated Spring Batch job. The main job configuration file is CrawlerJobConfiguration. Before now, I have all the configuration (infrastructure, autowired beans, etc) in this class and it works fine. So I decided to separate the job configuration from autowired beans and infracstruture beans configuration and create another 2 configuration classes Beans and MysqlInfrastructureConfiguration.
But now I am having problems to run my job. I'm receiving a NullPointerException when the application try to use autowired fields indicating that the autowired is not working.
I put a breakpoint in the methods that create autowired beans to make sure that they are being called and really are, so I cannot realize what can be the problem.
java.lang.NullPointerException: null
at br.com.alexpfx.supermarket.batch.tasklet.StartCrawlerTasklet.execute(StartCrawlerTasklet.java:27) ~[classes/:na]
at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406) ~[spring-batch-core-3.0.6.RELEASE.jar:3.0.6.RELEASE]
Main job configuration class:
#Configuration
#EnableBatchProcessing
public class CrawlerJobConfiguration {
#Autowired
private InfrastructureConfiguration infrastructureConfiguration;
#Autowired
private StepBuilderFactory steps;
#Autowired
Environment environment;
#Bean
public Job job(JobBuilderFactory jobs) {
Job theJob = jobs.get("job").start(crawlerStep()).next(processProductStep()).build();
((AbstractJob) theJob).setRestartable(true);
return theJob;
}
#Bean
public Step crawlerStep() {
TaskletStep crawlerStep = steps.get("crawlerStep").tasklet(crawlerTasklet()).build();
crawlerStep.setAllowStartIfComplete(true);
return crawlerStep;
}
#Bean
public Step processProductStep() {
TaskletStep processProductStep = steps.get("processProductStep")
.<TransferObject, Product>chunk(10)
.reader(reader())
.processor(processor())
.writer(writer())
.build();
processProductStep.setAllowStartIfComplete(true);
return processProductStep;
}
private Tasklet crawlerTasklet() {
return new StartCrawlerTasklet();
}
private ItemProcessor<TransferObject, Product> processor() {
return new ProductProcessor();
}
private ItemReader<TransferObject> reader() {
return new ProductItemReader();
}
private ItemWriter<Product> writer() {
return new HibernateProductsItemWriter();
}
}
Beans configuration class:
#Configuration
#EnableBatchProcessing
public class Beans {
#Bean
public Crawler crawler() {
return new RibeiraoCrawler(new UserAgentFactory());
}
#Bean
public ProductBo productBo() {
return new ProductBoImpl();
}
#Bean
public ProductDao productDao() {
return new ProductDaoImpl();
}
#Bean
public CrawlerListener listener() {
CrawlerListener listener = new RibeiraoListener();
return listener;
}
#Bean
public ProductList getProductList() {
return new ProductList();
}
}
MysqlInfrastructureConfiguration:
#Configuration
#EnableBatchProcessing
#PropertySource("classpath:database.properties")
#EnableJpaRepositories(basePackages = {"br.com.alexpfx.supermarket.domain"})
public class MysqlInfrastructureConfiguration implements InfrastructureConfiguration {
#Value("${jdbc.url}")
String url;
#Value("${jdbc.driverClassName}")
String driverClassName;
#Value("${jdbc.username}")
String username;
#Value("${jdbc.password}")
String password;
#Bean
#Override
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
#Bean
#Override
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
transactionManager.setDataSource(getDataSource());
return transactionManager;
}
#Bean
#Override
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(getDataSource());
em.setPackagesToScan(new String[]{"br.com.alexpfx.supermarket.domain"});
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalJpaProperties());
em.afterPropertiesSet();
return em.getObject();
}
private Properties additionalJpaProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.setProperty("hibernate.show_sql", "true");
properties.setProperty("current_session_context_class", "thread");
return properties;
}
}
tasklet:
public class StartCrawlerTasklet implements Tasklet {
#Autowired
private Crawler crawler;
#Autowired
private CrawlerListener listener;
#Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
crawler.setListener(listener);
crawler.setStopCondition(new TimeLimitStopCondition(1, TimeUnit.MINUTES));
crawler.crawl();
return RepeatStatus.FINISHED;
}
}
StartCrawlerTasklet use the autowired annotation, so it should be a bean as well. So change your code :
private Tasklet crawlerTasklet() {
return new StartCrawlerTasklet();
}
to a bean definition:
#Bean
public Tasklet crawlerTasklet() {
return new StartCrawlerTasklet();
}