#Converter annotated class not getting auto detected in spring-boot project - spring

I am using spring-boot 1.2.2 with hibernate.version:4.3.6.Final for a simple operation and was using the #Converter for mapping java8 LocalDateTime field to timestamp.
In my converter class, I used autoApply=true as below.
#Converter(autoApply = true)
public class LocalDateTimePersistenceConverter implements
AttributeConverter {
#Override
public java.sql.Timestamp convertToDatabaseColumn(LocalDateTime entityValue) {
return Timestamp.valueOf(entityValue);
}
#Override
public LocalDateTime convertToEntityAttribute(java.sql.Timestamp databaseValue) {
return databaseValue.toLocalDateTime();
}
}
However, I still have to use the #Convert on my entity.
The converter class is part of the packages I scan.
Is it something that I have to do to get this to work automatically without using the #Convert on all DB entries?
::Additionally::
Here is my DB Config
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource());
lef.setJpaVendorAdapter(jpaVendorAdapter());
lef.setPackagesToScan("path to domain and Converter class");
lef.afterPropertiesSet();
return lef;
}
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setDatabase(Database.ORACLE);
adapter.setShowSql(false);
adapter.setGenerateDdl(false);
return adapter;
}

The only thing I can see is you may need to change this line below
public class LocalDateTimePersistenceConverter implements
AttributeConverter<java.sql.Timestamp, LocaleDateTime>
Therefore, Spring would know how to automatically convert which type of attributes.

The order is incorrect, it should be:
public class LocalDateTimePersistenceConverter implements
AttributeConverter<LocaleDateTime, java.sql.Timestamp>
As the Javadoc states:
javax.persistence.AttributeConverter<X, Y>
Parameters:
X the type of the entity attribute
Y the type of the database column

Related

NoUniqueBeanDefinitionException when setting up multiple JPA datasources

I've followed many tutorials and reviewed many answers (in SO and other sites), and I'm quite confident I didn't miss anything, but I can't get two datasources/EntityManagers to work in my environment.
This is what I have
DbADataSourceConfig.java
package com.myorg.rest.config.dba;
import ...
#Configuration
// #EnableJpaRepositories(
// basePackages = "com.myorg.rest.dao.dbA",
// entityManagerFactoryRef = "dbAEntityManager",
// transactionManagerRef = "dbATransactionManager"
// )
#EnableTransactionManagement
public class DbADataSourceConfig {
#Autowired
private EnvProperties settings;
#Bean
#Primary
public DataSource prjDataSource() {
DataSourceProperties ds = settings.getdbADatasource();
return ds.initializeDataSourceBuilder().type(BasicDataSource.class).build();
}
#Bean(name = "dbAEntityManager")
#Primary
public LocalContainerEntityManagerFactoryBean dbAEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(prjDataSource());
em.setPackagesToScan(new String[] { "com.myorg.model.entities.dba" });
em.setPersistenceUnitName("dbAUnit");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
// em.afterPropertiesSet();
return em;
}
#Bean(name = "dbATransactionManager")
#Primary
public PlatformTransactionManager dbATransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(dbAEntityManager().getObject());
return transactionManager;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return properties;
}
}
DbBDataSourceConfig.java
package com.myorg.rest.config.dbb;
import ...
#Configuration
// #EnableJpaRepositories(
// basePackages = "com.myorg.rest.dao.dbB",
// entityManagerFactoryRef = "dbBEntityManager",
// transactionManagerRef = "dbBTransactionManager"
// )
#EnableTransactionManagement
public class DbBDataSourceConfig {
#Autowired
private EnvProperties settings;
#Bean
#Primary
public DataSource prjDataSource() {
DataSourceProperties ds = settings.getdbBDatasource();
return ds.initializeDataSourceBuilder().type(BasicDataSource.class).build();
}
#Bean(name = "dbBEntityManager")
#Primary
public LocalContainerEntityManagerFactoryBean dbBEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(prjDataSource());
em.setPackagesToScan(new String[] { "com.myorg.model.entities.dbb" });
em.setPersistenceUnitName("dbBUnit");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
// em.afterPropertiesSet();
return em;
}
#Bean(name = "dbBTransactionManager")
#Primary
public PlatformTransactionManager dbBTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(dbBEntityManager().getObject());
return transactionManager;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return properties;
}
}
AbstractDBADAO.java
package com.myorg.rest.dao.dba.base;
public abstract class AbstractDBADAO<T extends Serializable> implements IAbstractJpaDAO<T> {
private Class<T> clazz;
#PersistenceContext(unitName = "dbAUnit")
private EntityManager entityManager;
public AbstractDBADAO(Class<T> clazzToSet) {
this.clazz = clazzToSet;
}
public T findOne(String id) {
return entityManager.find(clazz, id);
}
public List<T> findAll() {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<T> entityQuery = criteriaBuilder.createQuery(clazz);
entityQuery.from(clazz);
return entityManager.createQuery(entityQuery).getResultList();
}
public void create(T entity) {
entityManager.persist(entity);
}
public T update(T entity) {
return entityManager.merge(entity);
}
public void delete(T entity) {
entityManager.remove(entity);
}
public void deleteById(String entityId) {
T entity = findOne(entityId);
delete(entity);
}
}
and last IAbstractJpaDAO.java
package com.myorg.rest.dao.dba.base;
import ...
public interface IAbstractJpaDAO<T extends Serializable> {
T findOne(String id);
List<T> findAll();
void create(T entity);
T update(T entity);
void delete(T entity);
void deleteById(String entityId);
}
Of course, there's also a bunch of #Repositorys extending IAbstractDAO interface and a corresponding bunch of #Services extending AbstractDAO<T>, but those are just skeletons like
EntityARepo.java
package com.myorg.rest.dao.dba.repositories;
import ...
#Repository
public interface EntityARepo extends IAbstractJpaDAO<EntityA> {
}
EntityAService.java
package com.myorg.rest.dao.dba.services;
import ...
#Service
public class EntityAService extends AbstractDBADAO<EntityA> implements EntityARepo {
public EntityAService() {
super(EntityA.class);
}
}
Similarly, there's a whole bunch of clases set up for the second database (dbB).
The problem
No matter what I do, I get the following problem (or something very similar):
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManager' available: expected single matching bean but found 2: org.springframework.orm.jpa.SharedEntityManagerCreator#0,org.springframework.orm.jpa.SharedEntityManagerCreator#1
at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:220)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1285)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1227)
From what I understand, the #PersistenceContext can not resolve to the correct LocalContainerEntityManagerFactoryBean. They both have setPersistenceUnitName('dbXUnit'), so they should be able to get resolved correctly, right?.
I do not have any persistence.xml file, I'm doing everything programmatically.
What I've tried so far
Obviously, the code above.
Also, you will notice there's a commented section for #EnableJpaRepositories; that doesn't work either.
I've also tried to build a PersistenceUnitManager for each of the DataSource config classes to no success.
I've tried #Autowired, with and without the #PersistenceContext, no luck either.
I've tried #PersistenceContext on a setter and using #Qualifier on the input EntityManager, no luck either.
I've tried with and without the #Primary decorators.
Please keep in mind any inconsistencies between the files above posted are surely a copy/paste error, I've had to edit names in order to keep confidentiality. Also note that the code I have compiles, runs, and doesn't output any other errors except for the one listed above. Also, with only one of those Database Config classes set up, the project runs as expected, and I can execute the tests on that connection.
The question
Can anyone spot why the #PersistenceContext is not wiring the
correct dependency and complains of a duplicate? or
Should I do things in a completely different manner?
You are going the correct way so far.
You need 2 of each:
EntityManager/factory
DataSource
TransactionManager
JPARepository-Configs
The key to success is IMO the correct and unique naming of them all (2x4=8 different names). #Primary and #Secondary do not help here.

Spring Data with JPA not rolling back transaction on error

We have Spring Data configured for JPA. A Service Transaction method doesn't get rolled back for an error (e.g. a DB ConstraintViolationException).
The closest I could find was this
(Transaction not rolling back) Spring-data, JTA, JPA, Wildfly10
but we don't have any XML configuration, all of our configuration is Java-based.
Essentially, a service method looks like this: no errors are caught, everything thrown.
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, readOnly = false)
public void insertEvent() throws Exception {
// Part 1
EventsT event = new EventsT();
// populate it..
eventsDAO.save(event);
// Part 2 - ERROR HAPPENS HERE (Constraint Violation Exception)
AnswersT answer = new AnswersT();
// populate it..
answersDAO.save(answer);
}
Part 2 fails. But after the error and return, I see that the Event (Part 1) is still populated in the DB.
We also tried various combinations of #Transactional, nothing worked:
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, readOnly = false)
#Transactional(readOnly = false)
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = ConstraintViolationException.class, readOnly = false)
Spring Data CRUD DAO Interfaces:
#Repository
public interface EventsDAO extends JpaRepository<EventsT, Integer> {
}
#Repository
public interface AnswersDAO extends JpaRepository<AnswersT, Integer> {
}
JpaConfig:
#Configuration
#EnableJpaRepositories(basePackages = "com.myapp.dao")
#PropertySource({ "file:${conf.dir}/myapp/db-connection.properties" })
public class JpaConfig {
#Value("${jdbc.datasource}")
private String dataSourceName;
#Bean
public Map<String, Object> jpaProperties() {
Map<String, Object> props = new HashMap<String, Object>();
props.put("hibernate.dialect", PostgreSQL95Dialect.class.getName());
//props.put("hibernate.cache.provider_class", HashtableCacheProvider.class.getName());
return props;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(true);
hibernateJpaVendorAdapter.setGenerateDdl(true);
hibernateJpaVendorAdapter.setDatabase(Database.POSTGRESQL);
return hibernateJpaVendorAdapter;
}
#Bean
public PlatformTransactionManager transactionManager() throws NamingException {
return new JpaTransactionManager( entityManagerFactory().getObject() );
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource());
lef.setJpaPropertyMap(this.jpaProperties());
lef.setJpaVendorAdapter(this.jpaVendorAdapter());
lef.setPackagesToScan("com.myapp.domain", "com.myapp.dao");
return lef;
}
#Bean
public DataSource dataSource() throws NamingException {
return (DataSource) new JndiTemplate().lookup(dataSourceName);
}
}
Have there been any transaction rollback issues with Spring Data & JPA?
Believe it or not we fixed it. There were 2 parts to the solution:
1) Add #EnableTransactionManagement to JpaConfig as ledniov described, but that alone wasn't enough;
2) Also in JpaConfig in entityManagerFactory(), add the Service class package to the following setPackagesToScan. Previously, the domain object package was there, but the service object package was not. We added "myapp.service", the 2nd package.
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource());
lef.setJpaPropertyMap(this.jpaProperties());
lef.setJpaVendorAdapter(this.jpaVendorAdapter());
lef.setPackagesToScan("myapp.domain", "myapp.service"); //NOTE: Service was missing
return lef;
}
You have to add #EnableTransactionManagement annotation to JpaConfig class in order to enable Spring's annotation-driven transaction management capability.

Spring JPA+Hibernate not able to fetch record using findAll() of JPARepository

I have created configuration using below code :
#Configuration
#EnableTransactionManagement
#ComponentScan("Name of package")
#EnableJpaRepositories("Name of package")
public class Config {
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "Name of package";
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("Driver Name");
dataSource.setUrl("Url");
dataSource.setUsername("UserName");
dataSource.setPassword("Password");
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
entityManagerFactoryBean.setPackagesToScan(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN);
entityManagerFactoryBean.setJpaProperties(hibProperties());
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return entityManagerFactoryBean;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, "org.hibernate.dialect.DB2Dialect");
properties.put("hibernate.default_schema","Schema Name");
return properties;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
}
There is an custom repository interface that implements JPARepository.
I have autowired the custom repository in controller and tried to call findAll().But the method returns 0 although there are 3 records in DB.
I am using spring web for rest service calls.
Entity class is created with #Entity and #Table annotations.It has an embedded key which is annotated using #EmbeddedId annotation.
#Repository
public interface EntityRepository extends JpaRepository<EntityTable, Long> {
#SuppressWarnings("unchecked") EntityTable save(EntityTable entityTable);
}
Entity table is the name of my table mapped with db table.

Spring Data REST, cannot save, can select

I'm puzzled as to why my Spring Data REST code was working, but not anymore. Probably a configuration issue, but I can't point my finger to what. When I use AJAX to post to a endpoint, I get a 500 error - java.lang.IllegalArgumentException: argument type mismatch. When I try repository.save() from independent java, I get no response. On the other hand, when I perform a get to my API or call repository.find(), I can see Hibernate showing selects happening. So I know that my database is connected. Additionally, I'm using Flyway and those scripts are able to insert without issue.
I'm using Spring-Boot-Starter for Data-REST, Data-JPA, and thymeleaf, all Version 1.2.1.RELEASE. I recognize that this could be a version issue, but I'm keeping it here to eventually integrate with Spring-Security-Kerberos, which I know works with that version of Spring-Boot. At least, I haven't gotten it to work with a later version of Spring-Boot.
Some things I have noticed that may or may not be related:
#Transactional on top my #RestRepositoryResource makes no difference
When calling repository.save(), the returned entity's ID stays at 0 (I'm Auto generation on my entities)
The problem exists on all my entities, including ones without any relations
It didn't matter that I removed unique=true from one of my entities
One of my Repository Interfaces
#RepositoryRestResource(collectionResourceRel = "shifts", path = "shifts")
public interface ShiftRepository extends PagingAndSortingRepository<Shift, Long> {
List<Shift> findBySiteId(#Param("siteId") String siteId);
Shift findByShiftCode(#Param("shiftCode") String shiftCode);
}
My Repository Config Component
#Component
public class RepositoryConfigDev {
#Value("${spring.datasource.driver-class-name}")
private String driverClassName;
#Value("${spring.datasource.url}")
private String url;
#Value("${spring.datasource.username}")
private String username;
#Value("${spring.datasource.password}")
private String password;
#Bean
EventHandler eventHandler() {
return new EventHandler();
}
#Bean
DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName(driverClassName);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setDatabase(Database.SQL_SERVER);
adapter.setDatabasePlatform("org.hibernate.dialect.SQLServer2012Dialect");
adapter.setShowSql(true);
adapter.setGenerateDdl(false);
return adapter;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean emfb = new LocalContainerEntityManagerFactoryBean();
emfb.setJpaVendorAdapter(jpaVendorAdapter());
emfb.setDataSource(dataSource());
emfb.setPackagesToScan("package.model");
emfb.afterPropertiesSet();
return emfb;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory().getObject());
txManager.setRollbackOnCommitFailure(true);
return txManager;
}
}
So after rebuilding from scratch, I figured out what I did wrong. The problem was in the #RepositoryEventHandler. In that I had originally declared the class as
#RepositoryEventHandler(value={Class1.class, Class2.class})
public class RepoEvents {
....
}
When it should have been
#RepositoryEventHandler
public class RepoEvents {
#HandleBeforeCreate(Class1.class)
public void beforeCreate1(Class1 c) { ... }
#HandleBeforeCreate(Class2.class)
public void beforeCreate2(Class2 c) { ... }
}

JPA with Spring MVC Configured via Annotations

I am trying to create a Spring MVC application leveraging JPA for its persistence layer. Unfortunately, I was getting a NullPointerException when accessing the EntityManager as Spring does not appear to be injecting it. My configuration is all annotation-based with #EnableWebMvc. After some searching, I added #Transactional on my DAO and #EnableTransactionManagement on my #Configuration class. Then I got an error about not having a DataSource. Supposedly, a class with #EnableTransactionManagement needs to implement TransactionManagementConfigurer. However, I am having problems figuring out how to create the DataSource as well as why it cannot get it from my persistence.xml.
I would greatly appreciate any help in trying to get the EntityManager injected into my DAO.
My #Configuration class
#Configuration
#EnableWebMvc
#EnableTransactionManagement
#ComponentScan("com.example.myapp")
public class MvcConfig extends WebMvcConfigurerAdapter
implements TransactionManagementConfigurer {
private static final boolean CACHE_ENABLED = true;
private static final String TEMPLATE_PATH = "/WEB-INF/freemarker";
private static final String TEMPLATE_SUFFIX = ".ftl";
private static final Logger LOG = Logger.getLogger( MvcConfig.class );
#Override
public void addResourceHandlers( ResourceHandlerRegistry registry ) {
registry.addResourceHandler( "/stylesheets/**" ).addResourceLocations( "/stylesheets/" );
}
#Bean
public FreeMarkerConfigurer configureFreeMarker() {
final FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath( TEMPLATE_PATH );
return configurer;
}
#Bean
public ViewResolver configureViewResolver() {
final FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
resolver.setCache( CACHE_ENABLED );
resolver.setSuffix( TEMPLATE_SUFFIX );
return resolver;
}
#Bean
#Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new DataSourceTransactionManager();
}
}
My DAO
#Component
#Transactional
public class MyDAO {
private static final Logger LOG = Logger.getLogger( MyDAO.class );
#PersistenceContext
private EntityManager entityManager;
public MyClass getMyClass() {
LOG.debug( "getMyClass()" );
final CriteriaQuery<MyClass> query = criteriaBuilder.createQuery( MyClass.class );
// more code here, but it breaks by this point
return myData;
}
}
My Updated Code
I have reached the point in which it almost all works. The EntityManager is being injected properly. However, transactions are not working. I get errors if I try to use a RESOURCE_LOCAL approach so I am looking at JTA managed transactions. When I add #Transactional on any of my DAO methods, I get a "Transaction marked for rollback" error with no further details in any log files to assist troubleshooting. If I remove the annotation from a basic read-only select, the select will work perfectly fine (not sure if I should even be putting the annotation on select-only methods). However, I obviously need this working on methods which perform db writes. If I debug through the code, it seems to retrieve the data perfectly fine. However, as it returns from the method, the javax.transaction.RollbackException gets thrown. From my understanding of everything, it seems as if the exception occurs in the AOP post-method processing.
My #Configuration class
#Configuration
#EnableWebMvc
#EnableTransactionManagement
#ComponentScan("com.example.myapp")
public class MvcConfig extends WebMvcConfigurerAdapter {
private static final boolean CACHE_ENABLED = true;
private static final String TEMPLATE_PATH = "/WEB-INF/freemarker";
private static final String TEMPLATE_SUFFIX = ".ftl";
private static final Logger LOG = Logger.getLogger( MvcConfig.class );
#Override
public void addResourceHandlers( ResourceHandlerRegistry registry ) {
registry.addResourceHandler( "/stylesheets/**" ).addResourceLocations( "/stylesheets/" );
}
#Bean
public FreeMarkerConfigurer configureFreeMarker() {
final FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath( TEMPLATE_PATH );
return configurer;
}
#Bean
public ViewResolver configureViewResolver() {
final FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
resolver.setCache( CACHE_ENABLED );
resolver.setSuffix( TEMPLATE_SUFFIX );
return resolver;
}
#Bean
public PlatformTransactionManager transactionManager() {
return new JtaTransactionManager();
}
#Bean
public AbstractEntityManagerFactoryBean entityManagerFactoryBean() {
LocalEntityManagerFactoryBean factory = new LocalEntityManagerFactoryBean();
factory.setPersistenceUnitName( "my_db" );
return factory;
}
}
In my application I didn't implement TransactionManagerConfigurer interface. I use next code to configure JPA (with Hibernate implementation). You can do the same in your configuration class.
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
LocalContainerEntityManagerFactoryBean factoryBean =
new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan(new String[] {"com.dimasco.springjpa.domain"});
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setShowSql(true);
//vendorAdapter.setGenerateDdl(generateDdl)
factoryBean.setJpaVendorAdapter(vendorAdapter);
Properties additionalProperties = new Properties();
additionalProperties.put("hibernate.hbm2ddl.auto", "update");
factoryBean.setJpaProperties(additionalProperties);
return factoryBean;
}
#Bean
public DataSource dataSource() {
final ComboPooledDataSource dataSource = new ComboPooledDataSource();
try {
dataSource.setDriverClass(driverClass);
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
dataSource.setJdbcUrl(jdbcUrl);
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setMinPoolSize(3);
dataSource.setMaxPoolSize(15);
dataSource.setDebugUnreturnedConnectionStackTraces(true);
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject());
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
Hope this will help you)
EDIT:
You can get datasource using JNDI lookup:
#Bean
public DataSource dataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
More details you can find in this article. There is example with JndiDatasourceConfig class.
EDIT 2:
I ahve persistence.xml in my project, but it is empty:
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="JPA_And_Spring_Test">
</persistence-unit>
</persistence>
And I didn't specify any persistent unit name in my java configuration.
The following might help, even though it uses XML-based configuration:
https://github.com/springinpractice/sip13/blob/master/helpdesk/src/main/resources/spring/beans-repo.xml
It uses Spring Data JPA, but you don't have to do that. Use
#PersistenceContext private EntityManager entityManager;
(But consider Spring Data JPA as it provides very capable DAOs out of the box.)
Side note: For DAOs, favor #Repository over #Component. Both work for component scanning, but #Repository better describes the intended use.

Resources