Reputation: 1394
I am trying to create a simple JAR with Spring + Spring Data + Hibernate capabilities. This is working when I have just put Spring or Hibernate + JPA separated but not when I am putting all them together.
Is this type of configuration possible?
I am using Maven assembly plugin just to create a JAR with dependencies.
I am also indicating the concrete packages to scan the JPA entities and it works with eclipse but not when I execute the single JAR.
My configuration is XML-free (there are not persistence.xml or application.xml) and now is looking for persistence.xml. if I put the file in META-INF/persisntece.xml the error is the same.
Updated: ConfigPersistence
@Configuration
@ComponentScan(basePackageClasses=_PackageTypeSafeClassModel.class)
@EnableJpaRepositories(basePackageClasses=_PackageTypeSafeClassModelRepositories.class)
@EnableTransactionManagement
@Import(ConfigProperties.class)
public class ConfigPersistence {
private static final Logger LOGGER = LoggerFactory.getLogger(LogNames.CONFIGURATION.toString());
/* Connection properties */
@Value("${db.user}") private String propDBUser;
@Value("${db.pass}") private String propDBPass;
@Value("${db.host}") private String propDBHost;
@Value("${db.port}") private String propDBPort;
@Value("${db.database}") private String propDBDatabase;
/* Pool properties */
@Value("${db.pool.datasource}") private String propDatasource;
@Value("${db.pool.setMinimumIdle}") private Integer propSetMinimumIdle;
@Value("${db.pool.setIdleTimeout}") private Integer propSetIdleTimeout;
@Value("${db.pool.setMaximumPoolSize}") private Integer propSetMaximumPoolSize;
@Value("${db.pool.setConnectionTimeout}") private Integer propSetConnectionTimeout;
/* Hibernate properties */
@Value("${db.hibernate.hbm2ddl.auto}") private String propHibernateHbm2ddl;
@Value("${db.hibernate_dialect}") private String propHibernateDialect;
@Value("${db.hibernate.show_sql}") private String propHibernateShowSql;
@Value("${db.hibernate.format_sql}") private String propHibernateFormatSql;
@Value("${db.hibernate.generate_statistics}") private String propHibernateStatistics;
@Value("${db.hibernate.use_sql_comments}") private String propHibernateSqlComments;
@Value("${db.hibernate.connection.autocommit}") private String propHibernateAutocommit;
@Value("${db.hibernate.mapping.precedence}") private String propHibernatePrecedence;
@Bean
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPackagesToScan(_PackageTypeSafeClassModelEntities.class.getPackage().getName());
entityManagerFactoryBean.setJpaVendorAdapter( new HibernateJpaVendorAdapter() );
entityManagerFactoryBean.setJpaProperties(hibernateProperties());
entityManagerFactoryBean.afterPropertiesSet();
return entityManagerFactoryBean.getObject();
}
@Bean
public DataSource dataSource() {
HikariDataSource hikariDS = new HikariDataSource();
/* Hikari Pool configuration */
hikariDS.setPoolName( "HikariCP pool" );
hikariDS.setDataSourceClassName( propDatasource );
hikariDS.setMinimumIdle( propSetMinimumIdle );
hikariDS.setIdleTimeout( propSetIdleTimeout ); // Minutes
hikariDS.setMaximumPoolSize( propSetMaximumPoolSize ); // Connection pool size
hikariDS.setConnectionTimeout( propSetConnectionTimeout ); // Miliseconds
/* Database configuration */
hikariDS.addDataSourceProperty("serverName", propDBHost );
hikariDS.addDataSourceProperty("portNumber", propDBPort );
hikariDS.addDataSourceProperty("databaseName", propDBDatabase );
hikariDS.addDataSourceProperty("user", propDBUser );
hikariDS.addDataSourceProperty("password", propDBPass );
LOGGER.info("Database connection to: {}:{}, database {} with user {}",
propDBHost, propDBPort, propDBDatabase, propDBUser);
return hikariDS;
}
@Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
@Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
private Properties hibernateProperties(){
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.dialect", propHibernateDialect );
hibernateProperties.setProperty("hibernate.ejb.entitymanager_factory_name", "myEntityManager");
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", propHibernateHbm2ddl );
hibernateProperties.setProperty("hibernate.show_sql", propHibernateShowSql );
hibernateProperties.setProperty("hibernate.format_sql", propHibernateFormatSql );
hibernateProperties.setProperty("hibernate.generate_statistics", propHibernateStatistics );
hibernateProperties.setProperty("hibernate.use_sql_comments", propHibernateSqlComments );
hibernateProperties.setProperty("hibernate.connection.autocommit", propHibernateAutocommit );
hibernateProperties.setProperty("hibernate.mapping.precedence", propHibernatePrecedence);
LOGGER.info("Setting {} hibernateProperties {}", hibernateProperties.size(), hibernateProperties);
return hibernateProperties;
}
}
The error that I am getting:
Caused by: javax.persistence.PersistenceException: Unable to resolve persistence unit root URL
at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.determineDefaultPersistenceUnitRootUrl(DefaultPersistenceUnitManager.java:591) ~[company-monitor-jar-with-dependencies.jar:na]
at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.preparePersistenceUnitInfos(DefaultPersistenceUnitManager.java:443) ~[company-monitor-jar-with-dependencies.jar:na]
at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.afterPropertiesSet(DefaultPersistenceUnitManager.java:424) ~[company-monitor-jar-with-dependencies.jar:na]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:310) ~[company-monitor-jar-with-dependencies.jar:na]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318) ~[company-monitor-jar-with-dependencies.jar:na]
at com.company.config.ConfigPersistence.entityManagerFactory(ConfigPersistence.java:88) ~[company-monitor-jar-with-dependencies.jar:na]
at com.company.config.ConfigPersistence$$EnhancerBySpringCGLIB$$a1e8e6cc.CGLIB$entityManagerFactory$1(<generated>) ~[company-monitor-jar-with-dependencies.jar:na]
at com.company.config.ConfigPersistence$$EnhancerBySpringCGLIB$$a1e8e6cc$$FastClassBySpringCGLIB$$17999b5a.invoke(<generated>) ~[company-monitor-jar-with-dependencies.jar:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[company-monitor-jar-with-dependencies.jar:na]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:318) ~[company-monitor-jar-with-dependencies.jar:na]
at com.company.config.ConfigPersistence$$EnhancerBySpringCGLIB$$a1e8e6cc.entityManagerFactory(<generated>) ~[company-monitor-jar-with-dependencies.jar:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_91]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_91]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_91]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162) ~[company-monitor-jar-with-dependencies.jar:na]
... 13 common frames omitted
Caused by: java.io.FileNotFoundException: class path resource [] cannot be resolved to URL because it does not exist
at org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:187) ~[company-monitor-jar-with-dependencies.jar:na]
at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.determineDefaultPersistenceUnitRootUrl(DefaultPersistenceUnitManager.java:588) ~[company-monitor-jar-with-dependencies.jar:na]
... 28 common frames omitted
[ERROR][CONFIGURATION] - [Main.java:30] - 24/05/2016 11:57:05.614 - Exception: Error creating bean with name 'entityManagerFactory' defined in com.company.config.ConfigPersistence: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.persistence.EntityManagerFactory]: Factory method 'entityManagerFactory' threw exception; nested exception is javax.persistence.PersistenceException: Unable to resolve persistence unit root URL
Updated: POM Dependencies
<dependencies>
<!-- Spring Boot dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<exclusions>
<exclusion>
<groupId>io.undertow</groupId>
<artifactId>undertow-websockets-jsr</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Databases dependencies -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>${database.oracle.version}</version>
</dependency>
<!-- Hibernate dependencies -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<!-- Connection pool -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<!-- Logging: SL4J and LogBack dependencies -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<!-- JCommander -->
<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
<version>${jcommander.version}</version>
</dependency>
</dependencies>
Upvotes: 0
Views: 2373
Reputation: 124898
Instead of trying to get a working solution using the maven-assembly-plugin
I would suggest using Spring Boot. That will already take care of those things like setting proper class loaders etc.
Start with translating your configuration into an application.properties
and use the Spring Boot property names. Then you can simply remove your configuration classes (as Spring Boot will auto detect what is on your classpath and configure accordingly).
Although as a migration strategy you could start with your own configuration classes, get it running and then strip everything that is provided for you (which is basically everything you have shown here).
Next create a starter class (in a top-level package so that it covers all packages).
@SpringBootApplication
public class MyApplication {
public static void main(String... args) throws Exception {
SpringApplication.run(MyApplication.class, args);
}
}
Your dependencies should look something like this. (deduced from your question but I assume there is a bit more).
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
</dependencies>
That is assuming that you use Spring Boot as a parent for your project.
Instead of the assembly plugin use the spring boot plugin.
<!-- Package as an executable jar -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
That should give you an executable jar without much effort and automatically bootstrapping your application.
Upvotes: 1
Reputation: 28726
According the stacktrace provided, you are using a LocalContainerEntityManagerFactoryBean and
LocalContainerEntityManagerFactoryBean creates a JPA EntityManagerFactory according to JPA's standard container bootstrap contract (source)
But Spring also provide LocalEntityManagerFactoryBean and
LocalEntityManagerFactoryBean creates a JPA EntityManagerFactory according to JPA's standard standalone bootstrap contract (source)
So first thing to do is to use a LocalEntityManagerFactoryBean. I don't know if it will solve all your problems, but at least, it's a first step if you are not running within a container.
Upvotes: 0