I want to configure Spring application with Hibernate. I tried this:
Main start method:
#Configuration
#EnableWebMvc
public class WebConfig implements WebApplicationInitializer, WebMvcConfigurer {
private BasicAuthenticationInterceptor basicAuthenticationInterceptor;
#Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.removeIf(converter -> converter instanceof MappingJackson2XmlHttpMessageConverter);
converters.removeIf(converter -> converter instanceof MappingJackson2HttpMessageConverter);
converters.add(new MappingJackson2XmlHttpMessageConverter(
((XmlMapper) createObjectMapper(Jackson2ObjectMapperBuilder.xml()))
.enable(ToXmlGenerator.Feature.WRITE_XML_DECLARATION)));
converters.add(new MappingJackson2HttpMessageConverter(
createObjectMapper(Jackson2ObjectMapperBuilder.json())));
}
private ObjectMapper createObjectMapper(Jackson2ObjectMapperBuilder builder) {
builder.indentOutput(true);
builder.modules(new JaxbAnnotationModule());
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
builder.defaultUseWrapper(false);
return builder.build();
}
#Override
public void onStartup(ServletContext container) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(ContextDatasource.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
#Autowired
public void setBasicAuthenticationInterceptor(BasicAuthenticationInterceptor basicAuthenticationInterceptor) {
this.basicAuthenticationInterceptor = basicAuthenticationInterceptor;
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(basicAuthenticationInterceptor);
}
}
Hibernate configuration called from rootContext.register(ContextDatasource.class);:
#SpringBootApplication
#Configuration
#EnableTransactionManagement
public class ContextDatasource {
#Bean
public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
return new FastJsonHttpMessageConverter();
}
#Bean
#Autowired
public HttpMessageConverters convertersToBeUsed(FastJsonHttpMessageConverter converter) {
return new HttpMessageConverters(converter);
}
#Bean
public LocalSessionFactoryBean getSessionFactory() throws NamingException {
final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(getDataSource());
sessionFactory.setPackagesToScan(new String[] { "org.datalis.plugin.database.models" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource getDataSource() throws NamingException {
return (DataSource) new JndiTemplate().lookup("java:/global/production_gateway");
}
#Bean
public PlatformTransactionManager getHibernateTransactionManager() throws NamingException {
final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(getSessionFactory().getObject());
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor getExceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private final Properties hibernateProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MariaDBDialect");
hibernateProperties.setProperty("hibernate.show_sql", "true");
hibernateProperties.setProperty("hibernate.format_sql", "true");
return hibernateProperties;
}
}
But when I deploy the WAR file I get error:
Caused by: java.lang.NoSuchMethodException: org.springframework.boot.autoconfigure.http.HttpMessageConverters$$EnhancerBySpringCGLIB$$1d90bff9.<init>()
at java.base/java.lang.Class.getConstructor0(Class.java:3302)
Full error stack:
https://pastebin.com/x30W2aws
Can you give advice where I'm wrong and how to fix the problem?
Do I need to implement the module startup with another configuration?
EDIT:
With Java 8 the code is working without above issue. With latest Java 10 I get the above exception. Do you know what configuration I need to do?
According to the Spring Boot release notes, Java 10 is supported by Spring Boot version 2.0.1 and up. Without a list of your dependencies it's impossible to know if this is the issue, but it does seem like a good place to start.
Are you running Boot v2.0.1 or higher?
Related
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};
}
}
I have already deploy war spring MVC to tomcat9. it's already running but in spring I create getmapping("/tesget") but when I created the servlet, result getmapping is wrong.
controller:
#GetMapping("tesget")
#ResponseStatus(HttpStatus.OK)
public List getTes2() throws Exception {
return userService.getTes2();
}
servlet:
public class Servlet extends HttpServlet {
public void init() throws ServletException
{
// Do required initialization
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.println("<HTML>");
out.println("<HEAD>");
out.println("<TITLE>Servlet Testing</TITLE>");
out.println("</HEAD>");
out.println("<BODY>");
out.println("Welcome to the Servlet Testing Center");
out.println("</BODY>");
out.println("</HTML>");
}
public void destroy()
{
// do nothing.
}
}
web.xml:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<servlet>
<servlet-name>Servlet</servlet-name>
<servlet-class>com.project.maven.config.Servlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Servlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Before I created servlet and war, I running usually and when I go to localhost:8080/SpringNew/tesget, the result is true, list JSON from database, but when I create servlet, the url localhost:8080/SpringNew/tesget is wrong. the result is:
Welcome to the Servlet Testing Center
how to fix this problem? Thanks.
Bobby
AppInitializer.java
public class AppInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
ctx.setServletContext(container);
ServletRegistration.Dynamic servlet = container.addServlet(
"dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
}
}
HibernateConfiguration.java
#Configuration
#EnableTransactionManagement
#ComponentScan({ "com.project.maven." })
#PropertySource(value = { "classpath:application.properties" })
public class HibernateConfiguration {
#Autowired
private Environment environment;
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "com.project.maven.entity" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
return dataSource;
}
private Properties hibernateProperties() {
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"));
return properties;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
}
AppConfig.java
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.project.maven")
public class AppConfig extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
registry.addResourceHandler("**/**")
.addResourceLocations("classpath:/META-INF/resources/"); // harus ada folder resources di webapp/WEB-INF/
}
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
what about your other config !
send your controller class code
if you are sure about your config try with #GetMapping("/tesget")
I am trying to move spring xml config to java config. Right now, I am able to make everything work, except one thing, that is to run junit on my services. The problem is that my junit test couldn't detect application context. Hence, how I can load application context java-based config in Junit? Since I can run my service on a browser, I assume that my integration is correct, meaning that my test configuration is not right, but I can't find where is my be wrong.
This is my junit config:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(
classes={Bootstrap.class, RootContextConfig.class
, WebServletContextConfig.class, PersistenceConfig.class })
#WebAppConfiguration
//#TransactionConfiguration(transactionManager="transactionManager",defaultRollback=true)
public class BaseTest { ... }
Just in case, I include my application context configuration here also.
This is my bootstrap
public class Bootstrap implements WebApplicationInitializer
{
#Override
public void onStartup(ServletContext container)
throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(RootContextConfig.class);
container.addListener(new ContextLoaderListener(rootContext));
AnnotationConfigWebApplicationContext servletContext = new AnnotationConfigWebApplicationContext();
servletContext.register(WebServletContextConfig.class);
ServletRegistration.Dynamic dispatcher = container.addServlet(
"SpringDispatcher", new DispatcherServlet(servletContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
My RootContext
#Configuration
#EnableScheduling
#EnableAsync(
mode=AdviceMode.PROXY, proxyTargetClass=false,
order=Ordered.HIGHEST_PRECEDENCE
)
#ComponentScan(
basePackages={"com.core", "com.common"},
excludeFilters=#ComponentScan.Filter(Controller.class)
)
#Import({PersistenceConfig.class})
public class RootContextConfig {...}
My WebServletContext
#Configuration
#EnableWebMvc
#ComponentScan(
basePackages = { "com.web" },
useDefaultFilters = false,
includeFilters = #ComponentScan.Filter({Controller.class, ControllerAdvice.class})
)
public class WebServletContextConfig extends WebMvcConfigurerAdapter {..}
My PersistentContext
#Configuration
#EnableTransactionManagement(
mode=AdviceMode.PROXY, proxyTargetClass=false
, order=Ordered.LOWEST_PRECEDENCE)
public class PersistenceConfig {
#Bean
public DataSource customerSupportDataSource() {
//JndiDataSourceLookup lookup = new JndiDataSourceLookup();\
BasicDataSource basic = new BasicDataSource();
basic.setDriverClassName(KEY_DRIVER_CLASS);
basic.setUrl(KEY_DB_URL);
basic.setUsername(KEY_DB_USERNAME);
basic.setPassword(KEY_DB_PASSWORD);
return basic;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean()
{
Map<String, Object> properties = new Hashtable<>();
properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQLDialect");
adapter.setGenerateDdl(true);
adapter.setShowSql(true);
LocalContainerEntityManagerFactoryBean factory =
new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(adapter);
factory.setDataSource(this.customerSupportDataSource());
factory.setPackagesToScan("com.common.model");
factory.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
factory.setValidationMode(ValidationMode.NONE);
factory.setJpaPropertyMap(properties);
return factory;
}
#Bean
public PlatformTransactionManager jpaTransactionManager()
{
return new JpaTransactionManager(
this.entityManagerFactoryBean().getObject()
);
}
}
I need to connect to two different databases from a single application. The trouble is that my appEntityManager does not have a transaction manager associated with it and I am not sure how to do it. The #Primary adminEntityManager is able to use the one provided by spring boot without any trouble as described here.
The configuration above almost works on its own. To complete the
picture you need to configure TransactionManagers for the two
EntityManagers as well. One of them could be picked up by the default
JpaTransactionManager in Spring Boot if you mark it as #Primary. The
other would have to be explicitly injected into a new instance. Or you
might be able to use a JTA transaction manager spanning both.
I have annoted the configuration with
#EnableTransactionManagement
And here is the relavant beans
#Bean
#ConfigurationProperties(prefix = "datasource.app")
public DataSource appDataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
#ConfigurationProperties(prefix = "datasource.admin")
public DataSource adminDataSource() {
return DataSourceBuilder.create().build();
}
#Bean
public LocalContainerEntityManagerFactoryBean appEntityManagerFactory(
final EntityManagerFactoryBuilder builder) {
return builder
.dataSource(appDataSource())
.packages("au.com.mycompany.app.bomcommon.domain")
.persistenceUnit("appPersistentUnit")
.build();
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean adminEntityManagerFactory(
final EntityManagerFactoryBuilder builder) {
return builder
.dataSource(adminDataSource())
.packages("au.com.mycompany.app.bombatch")
.persistenceUnit("adminPersistentUnit")
.build();
}
//I thought this would do it but I am getting an exception
//No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: appTransactionManager,transactionManager
#Bean
public JpaTransactionManager appTransactionManager(#Qualifier("appEntityManagerFactory") final EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
Update
I ended up doing it a different way. see here.
See if this works:
#Bean
#Primary
#ConfigurationProperties(prefix = "datasource.admin")
public DataSource adminDS() { ... }
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean adminEMF(...) { ... }
#Bean
#Primary
public JpaTransactionManager adminTM(...) { ... }
#Bean
public LocalContainerEntityManagerFactoryBean appEMF(...) { ... }
#Bean
public JpaTransactionManager appTM(...) { ... }
The only change I have made from your configuration is to declare a transaction manager for the admin side explicitly and marked that transaction manager as the default.
See the below changes. It works for me. Created 3 Data Sources, 3 Session Factories, and 3 Transaction Managers. Added these transaction managers in chainedTransaction as per below:
#Configuration
#EnableTransactionManagement
public class HibernateConfiguration implements TransactionManagementConfigurer {
#Bean("chainedTransactionManager")
public PlatformTransactionManager transactionManager(
#Qualifier("transactionManager1") final HibernateTransactionManager transactionManager1,
#Qualifier("transactionManager2") final HibernateTransactionManager transactionManager2,
#Qualifier("transactionManager3") final HibernateTransactionManager transactionManager3) {
return new ChainedTransactionManager(transactionManager1, transactionManager2, transactionManager3);
}
#Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
// TODO Auto-generated method stub
return transactionManager(oneTransactionManager(), twoTransactionManager(), threeTransactionManager());
}
#Bean(name = "oneDataSource", destroyMethod="")
public DataSource oneDataSource() throws IllegalArgumentException, NamingException, SQLException {
HikariConfig hkConfig = new HikariConfig();
System.out.println(env.getRequiredProperty("spring1-datasource.jdbcUrl"));
hkConfig.setJdbcUrl(env.getRequiredProperty("spring1-datasource.jdbcUrl"));
hkConfig.setUsername(env.getRequiredProperty("spring1-datasource.username"));
hkConfig.setPassword(env.getRequiredProperty("spring1-datasource.password"));
hkConfig.setDriverClassName(env.getRequiredProperty("spring1-datasource.driverClassName"));
return new HikariDataSource(hkConfig);
}
#Bean(name="oneSessionFactory")
#Qualifier("oneSessionFactory")
public LocalSessionFactoryBean oneSessionFactory() throws IllegalArgumentException, NamingException, SQLException {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(oneDataSource());
sessionFactory.setPackagesToScan(env.getRequiredProperty("entitymanager.packagesToScan"));
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
hibernateProperties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
sessionFactory.setHibernateProperties(hibernateProperties);
return sessionFactory;
}
#Bean(name="transactionManager1")
public HibernateTransactionManager oneTransactionManager() {
HibernateTransactionManager oneTransactionManager = new HibernateTransactionManager();
try {
oneTransactionManager.setSessionFactory(oneSessionFactory().getObject());
} catch (IllegalArgumentException | NamingException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return oneTransactionManager
}
#Bean(name = "twoDataSource", destroyMethod="")
public DataSource twoDataSource() throws IllegalArgumentException, NamingException, SQLException {
HikariConfig hkConfig = new HikariConfig();
System.out.println(env.getRequiredProperty("spring2-datasource.jdbcUrl"));
hkConfig.setJdbcUrl(env.getRequiredProperty("spring2-datasource.jdbcUrl"));
hkConfig.setUsername(env.getRequiredProperty("spring2-datasource.username"));
hkConfig.setPassword(env.getRequiredProperty("spring2-datasource.password"));
hkConfig.setDriverClassName(env.getRequiredProperty("spring2-datasource.driverClassName"));
return new HikariDataSource(hkConfig);
}
#Bean(name="twoSessionFactory")
#Qualifier("twoSessionFactory")
public LocalSessionFactoryBean twoSessionFactory() throws IllegalArgumentException, NamingException, SQLException {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(twoDataSource());
sessionFactory.setPackagesToScan(env.getRequiredProperty("entitymanager.packagesToScan"));
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
hibernateProperties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
sessionFactory.setHibernateProperties(hibernateProperties);
return sessionFactory;
}
#Bean(name="transactionManager2")
public HibernateTransactionManager twoTransactionManager() {
HibernateTransactionManager twoTransactionManager = new HibernateTransactionManager();
try {
twoTransactionManager.setSessionFactory(twoSessionFactory().getObject());
} catch (IllegalArgumentException | NamingException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return twoTransactionManager
}
#Bean(name = "threeDataSource", destroyMethod="")
public DataSource threeDataSource() throws IllegalArgumentException, NamingException, SQLException {
HikariConfig hkConfig = new HikariConfig();
System.out.println(env.getRequiredProperty("spring3-datasource.jdbcUrl"));
hkConfig.setJdbcUrl(env.getRequiredProperty("spring3-datasource.jdbcUrl"));
hkConfig.setUsername(env.getRequiredProperty("spring3-datasource.username"));
hkConfig.setPassword(env.getRequiredProperty("spring3-datasource.password"));
hkConfig.setDriverClassName(env.getRequiredProperty("spring3-datasource.driverClassName"));
return new HikariDataSource(hkConfig);
}
#Bean(name="threeSessionFactory")
#Qualifier("threeSessionFactory")
public LocalSessionFactoryBean threeSessionFactory() throws IllegalArgumentException, NamingException, SQLException {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(threeDataSource());
sessionFactory.setPackagesToScan(env.getRequiredProperty("entitymanager.packagesToScan"));
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
hibernateProperties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
sessionFactory.setHibernateProperties(hibernateProperties);
return sessionFactory;
}
#Bean(name="transactionManager3")
public HibernateTransactionManager threeTransactionManager() {
HibernateTransactionManager threeTransactionManager = new HibernateTransactionManager();
try {
threeTransactionManager.setSessionFactory(threeSessionFactory().getObject());
} catch (IllegalArgumentException | NamingException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return threeTransactionManager
}
}
I'm trying to update a project made with spring and hibernate with springboot.
Everything seems ok, but I can't figure how to get the entityManager.
I'm not using spring data, so no domain nor repository is used.
In this project, services are annotated with #service and entityManager is autowire with: #PersistenceContext,
here an example of my service
#Service
#Transactional
public class UserServiceImpl implements UserDetailsService, UserService {
#PersistenceContext
EntityManager entityManager;
/**
*
*/
private static final long serialVersionUID = 6384460058124202695L;
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
User user = entityManager.find(User.class, username);
return user;
}
The problem here is that the entityManager is null. So I read in doc that if we want to manage the entityManager we have to configure it, so I did this in configuration file:
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "services" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
The application is launching, but still have the entityManager null.
Any clue?
Edit: adding my application class (Has it's a demo project, I put all the config in one file)
#Configuration
#EnableAutoConfiguration
#ComponentScan
#EnableWebMvcSecurity
public class Application extends WebSecurityConfigurerAdapter{
#Value("${sec.cas.server}")
private String casServer;
#Value("${sec.app.server}")
private String appServer;
#Value("${spring.datasource.driverClassName}")
private String databaseDriverClassName;
#Value("${spring.datasource.url}")
private String databaseUrl;
#Value("${spring.datasource.username}")
private String databaseUsername;
#Value("${spring.datasource.password}")
private String databasePassword;
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
}
#Bean
public ComboPooledDataSource dataSource() {
ComboPooledDataSource datasource = new ComboPooledDataSource();
try {
datasource.setDriverClass(databaseDriverClassName);
} catch (PropertyVetoException e) {
throw new IllegalArgumentException("Wrong driver class");
}
datasource.setJdbcUrl(databaseUrl);
datasource.setUser(databaseUsername);
datasource.setPassword(databasePassword);
datasource.setAcquireIncrement(1);
datasource.setIdleConnectionTestPeriod(600);
datasource.setMaxPoolSize(500);
datasource.setMinPoolSize(50);
datasource.setMaxStatements(0);
datasource.setMaxConnectionAge(600);
datasource.setMaxIdleTime(600);
return datasource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
DefaultPersistenceUnitManager unitManager = new DefaultPersistenceUnitManager ();
unitManager.setDefaultDataSource(dataSource());
unitManager.setPersistenceXmlLocations("classpath*:META-INF/persistence.xml"); //location of your persistence.xml file
unitManager.setPackagesToScan(new String[] { "services" });
unitManager.setDefaultPersistenceUnitName("entityManager");
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPersistenceUnitManager(unitManager);
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.show_sql", "false");
properties.setProperty("hibernate.format_sql", "true");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.Oracle9iDialect");
return properties;
}
#Bean
public JdbcDaoImpl jdbcUserService() {
JdbcDaoImpl jdbcDaoImpl = new JdbcDaoImpl();
jdbcDaoImpl.setEnableGroups(true);
jdbcDaoImpl.setEnableAuthorities(true);
jdbcDaoImpl.setDataSource(dataSource());
return jdbcDaoImpl;
}
#Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService("http://"+appServer+"/j_spring_cas_security_check");
serviceProperties.setSendRenew(false);
return serviceProperties;
}
#Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setAuthenticationUserDetailsService(authenticationUserDetailsService());
casAuthenticationProvider.setUserDetailsService(new UserServiceImpl());
//casAuthenticationProvider.setAuthenticationUserDetailsService(userServiceImpl.class);
casAuthenticationProvider.setServiceProperties(serviceProperties());
casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
casAuthenticationProvider.setKey("an_id_for_this_auth_provider_only");
return casAuthenticationProvider;
}
#Bean
public UserDetailsByNameServiceWrapper authenticationUserDetailsService() {
UserDetailsByNameServiceWrapper userDetailsByName = new UserDetailsByNameServiceWrapper();
userDetailsByName.setUserDetailsService(jdbcUserService());
return userDetailsByName;
}
#Bean
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
Cas20ServiceTicketValidator casServiceTicketValidator = new Cas20ServiceTicketValidator("https://"+casServer+"/cas");
casServiceTicketValidator.setProxyCallbackUrl("http://"+appServer+"/");
casServiceTicketValidator.setProxyGrantingTicketStorage(new ProxyGrantingTicketStorageImpl());
return casServiceTicketValidator;
}
#Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setAuthenticationSuccessHandler(new SavedRequestAwareAuthenticationSuccessHandler());
casAuthenticationFilter.setProxyGrantingTicketStorage(new ProxyGrantingTicketStorageImpl());
casAuthenticationFilter.setProxyReceptorUrl("/secure/receptor");
return casAuthenticationFilter;
}
#Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl("https://"+casServer+"/cas/login");
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilter(casAuthenticationFilter());
http
.exceptionHandling()
.authenticationEntryPoint(casAuthenticationEntryPoint());
http
.authorizeRequests()
.antMatchers("/", "/home").authenticated()
.anyRequest().authenticated();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(casAuthenticationProvider());
}
Your EntityManager being null indicates that Spring isn't processing #PersistenceContext annotations in your UserServiceImpl instance.
You're creating an instance of UserServiceImpl manually as part of configuring your CasAuthenticationProvider bean. That means that Spring knows nothing about the instance and will not inject any of its dependencies. You need to use a Spring-created instance, for example by making it an argument of the casAuthenticationProvider() method.
Try:
DefaultPersistenceUnitManager unitManager = new DefaultPersistenceUnitManager();
unitManager.setPersistenceXmlLocations("classpath*:META-INF/persistence.xml"); //location of your persistence.xml file.
unitManager.setDefaultDataSource(dataSource);
In persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="entityManager" transaction-type="RESOURCE_LOCAL">
//classes, etc...
</persistence-unit>
</persistence>
and:
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPersistenceUnitManager(unitManager);
em.setPersistenceUnitName("entityManager");
And then injet:
#PersistenceContext(unitName = "entityManager")
private EntityManager entityManager;
That should work.
Solution by OP.
Got it finally worked, no entityManager is needed to be redefined, just add the bean who get the #persistenceContext (before spring boot 1.2.0)
Here is my application context:
#Configuration
#ComponentScan(basePackages={"services","model"})
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
#Bean
public PersistenceAnnotationBeanPostProcessor persistenceBeanPostProcessor() {
return new PersistenceAnnotationBeanPostProcessor();
}