I have one application that i install on different servers
each server has different jdbc name
the jdbc name also Defined under the (java) system-prop "jdbc_name" in all servers
i try to change "jta-data-source" dynamically to work with value from system-prop("jdbc_name")
for now
in my case i use
#PersistenceContext(unitName="MyUnit")
private EntityManager em;
persistence.xml:
<persistence-unit name="MyUnit" transaction-type="JTA">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<jta-data-source>jdbc/myJdbcName</jta-data-source>
<class>com.myCom.myClass</class>
<properties>
<property name="openjpa.TransactionMode" value="managed"/>
</properties>
</persistence-unit>
im using:
websphere
ejb3
openjpa
As far as i know, there is now way you can do this if you are using container-managed entity-managers.
You will have to resort back to application-managed entity-managers, and in order not to do the manual work, you can integrate this with CDI.
This will involve managing transaction boundaries manually. In order to avoid this kind of manual transaction boundary management, you can use interceptors:
#ApplicationEntityManagerInterceptorBinding
#Interceptor
public class ApplicationEntityManagerInterceptor {
#Inject
#ApplicationEntityManager
private EntityManager em;
#AroundInvoke
public Object intercept(final InvocationContext ic) {
//check if transaction is active, otherwise create a new one
em.createTransaction....
try {
return ic.proceed();
} catch (Exception ex) {
//does the exception require rollback? rollback the transaction here
} finally {
//commit the transaction if necessary.
}
}
}
#Stateless
public class EntityManagerFactoryProducer {
#Produces
#ApplicationEntityManager
public EntityManager entityManager() {
final EntityManagerFactory emf = Persistence.createEntityManager("persistence_name");
return emf.createEntityManager();
}
//you will have to manage this yourself
public void dispose(#Dispose final EntityManager em) {
em.close();
}
}
and then wherever you need it!
#Stateless
#ApplicationEntityManagerInterceptorBinding
public class MyDAO {
#Inject
#ApplicationEntityManager
private EntityManager em;
}
Related
I am new to Spring Transaction. Something that I found really odd, probably I did understand this properly.
I wanted to have a transactional around method level and I have a caller method within the same class and it seems like it does not like that, it has to be called from the separate class. I don't understand how is that possible.
If anyone has an idea how to resolve this issue, I would greatly appreciate. I would like to use the same class to call the annotated transactional method.
Here is the code:
public class UserService {
#Transactional
public boolean addUser(String userName, String password) {
try {
// call DAO layer and adds to database.
} catch (Throwable e) {
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
}
}
public boolean addUsers(List<User> users) {
for (User user : users) {
addUser(user.getUserName, user.getPassword);
}
}
}
It's a limitation of Spring AOP (dynamic objects and cglib).
If you configure Spring to use AspectJ to handle the transactions, your code will work.
The simple and probably best alternative is to refactor your code. For example one class that handles users and one that process each user. Then default transaction handling with Spring AOP will work.
Configuration tips for handling transactions with AspectJ
To enable Spring to use AspectJ for transactions, you must set the mode to AspectJ:
<tx:annotation-driven mode="aspectj"/>
If you're using Spring with an older version than 3.0, you must also add this to your Spring configuration:
<bean class="org.springframework.transaction.aspectj
.AnnotationTransactionAspect" factory-method="aspectOf">
<property name="transactionManager" ref="transactionManager" />
</bean>
In Java 8+ there's another possibility, which I prefer for the reasons given below:
#Service
public class UserService {
#Autowired
private TransactionHandler transactionHandler;
public boolean addUsers(List<User> users) {
for (User user : users) {
transactionHandler.runInTransaction(() -> addUser(user.getUsername, user.getPassword));
}
}
private boolean addUser(String username, String password) {
// TODO call userRepository
}
}
#Service
public class TransactionHandler {
#Transactional(propagation = Propagation.REQUIRED)
public <T> T runInTransaction(Supplier<T> supplier) {
return supplier.get();
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public <T> T runInNewTransaction(Supplier<T> supplier) {
return supplier.get();
}
}
This approach has the following advantages:
It may be applied to private methods. So you don't have to break encapsulation by making a method public just to satisfy Spring limitations.
Same method may be called within different transaction propagations and it is up to the caller to choose the suitable one. Compare these 2 lines:
transactionHandler.runInTransaction(() -> userService.addUser(user.getUserName, user.getPassword));
transactionHandler.runInNewTransaction(() -> userService.addUser(user.getUserName, user.getPassword));
It is explicit, thus more readable.
The problem here is, that Spring's AOP proxies don't extend but rather wrap your service instance to intercept calls. This has the effect, that any call to "this" from within your service instance is directly invoked on that instance and cannot be intercepted by the wrapping proxy (the proxy is not even aware of any such call). One solutions is already mentioned. Another nifty one would be to simply have Spring inject an instance of the service into the service itself, and call your method on the injected instance, which will be the proxy that handles your transactions. But be aware, that this may have bad side effects too, if your service bean is not a singleton:
<bean id="userService" class="your.package.UserService">
<property name="self" ref="userService" />
...
</bean>
public class UserService {
private UserService self;
public void setSelf(UserService self) {
this.self = self;
}
#Transactional
public boolean addUser(String userName, String password) {
try {
// call DAO layer and adds to database.
} catch (Throwable e) {
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
}
}
public boolean addUsers(List<User> users) {
for (User user : users) {
self.addUser(user.getUserName, user.getPassword);
}
}
}
With Spring 4 it's possible to Self autowired
#Service
#Transactional
public class UserServiceImpl implements UserService{
#Autowired
private UserRepository repository;
#Autowired
private UserService userService;
#Override
public void update(int id){
repository.findOne(id).setName("ddd");
}
#Override
public void save(Users user) {
repository.save(user);
userService.update(1);
}
}
This is my solution for self invocation:
public class SBMWSBL {
private SBMWSBL self;
#Autowired
private ApplicationContext applicationContext;
#PostConstruct
public void postContruct(){
self = applicationContext.getBean(SBMWSBL.class);
}
// ...
}
You can autowired BeanFactory inside the same class and do a
getBean(YourClazz.class)
It will automatically proxify your class and take into account your #Transactional or other aop annotation.
Here is what I do for small projects with only marginal usage of method calls within the same class. In-code documentation is strongly advised, as it may look strange to colleagues. But it works with singletons, is easy to test, simple, quick to achieve and spares me the full blown AspectJ instrumentation. However, for more heavy usage I'd advice the AspectJ solution as described in Espens answer.
#Service
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class PersonDao {
private final PersonDao _personDao;
#Autowired
public PersonDao(PersonDao personDao) {
_personDao = personDao;
}
#Transactional
public void addUser(String username, String password) {
// call database layer
}
public void addUsers(List<User> users) {
for (User user : users) {
_personDao.addUser(user.getUserName, user.getPassword);
}
}
}
The issue is related to how spring load classes and proxies. It will not work , untill you write your inner method / transaction in another class or go to other class and then again come to your class and then write the inner nested transcation method.
To summarize, spring proxies does not allow the scenarios which you are facing. you have to write the 2nd transaction method in other class
There is no point to use AspectJ or Other ways. Just using AOP is sufficient. So, we can add #Transactional to addUsers(List<User> users) to solve current issue.
public class UserService {
private boolean addUser(String userName, String password) {
try {
// call DAO layer and adds to database.
} catch (Throwable e) {
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
}
}
#Transactional
public boolean addUsers(List<User> users) {
for (User user : users) {
addUser(user.getUserName, user.getPassword);
}
}
}
I'm trying to setup a transactional ehcache, making use of Spring #Cacheable and #Transactional.
My caches work fine with #Cacheable, but as soon as i setup my cache to use a local transaction:
<cache name="currencyCodeMaps" maxElementsInMemory="100" overflowToDisk="false" timeToIdleSeconds="5" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU" transactionalMode="local"/>
When I access the cache i get error:
net.sf.ehcache.transaction.TransactionException: transaction not started
even though the same method is annotated #Transactional.
My Spring transaction manager is:
org.springframework.orm.jpa.JpaTransactionManager
The ehcache documentation says local transactions are controlled explicitly:
Local transactions are not controlled by a Transaction Manager.
Instead there is an explicit API where a reference is obtained to a
TransactionController for the CacheManager using
cacheManager.getTransactionController() and the steps in the
transaction are called explicitly
But this will be hard, as I want to sync my ehcache transactions with DB transactions, and DB transactions are controlled by #Transactional.
Is there a way to get local Ehcache transactions to work with Spring #Transactional?
Yes, there is a way to achieve you goal.
Because you have 2 transactional resources (JTA and Ehcache) and do not use JTA you have to use compound transaction manager likeorg.springframework.data.transaction.ChainedTransactionManager from spring-data project
#Bean
public PlatformTransactionManager transactionManager() {
return new ChainedTransactionManager(ehcacheTransactionManager(), jpaTransactionManager());
}
#Bean
public EhcacheTransactionManager ehcacheTransactionManager() {
return new EhcacheTransactionManager(ehcacheManager().getTransactionController());
}
#Bean
public PlatformTransactionManager jpaTransactionManager() {
return new JpaTransactionManager(entityManagerFactory());
}
You need to specify which transaction manager should be use by default:
#Configuration
public class Configuration implements TransactionManagementConfigurer {
...
#Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return transactionManager();
}
...
}
EhcacheTransactionManager implementation
import net.sf.ehcache.TransactionController;
import net.sf.ehcache.transaction.local.LocalTransactionContext;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
public class EhcacheTransactionManager extends AbstractPlatformTransactionManager {
private TransactionController transactionController;
public EhcacheTransactionManager(TransactionController transactionController) {
this.transactionController = transactionController;
}
#Override
protected Object doGetTransaction() throws TransactionException {
return new EhcacheTransactionObject(transactionController.getCurrentTransactionContext());
}
#Override
protected void doBegin(Object o, TransactionDefinition transactionDefinition) throws TransactionException {
int timeout = transactionDefinition.getTimeout();
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
transactionController.begin(timeout);
} else {
transactionController.begin();
}
}
#Override
protected void doCommit(DefaultTransactionStatus defaultTransactionStatus) throws TransactionException {
transactionController.commit();
}
#Override
protected void doRollback(DefaultTransactionStatus defaultTransactionStatus) throws TransactionException {
transactionController.rollback();
}
public class EhcacheTransactionObject {
private LocalTransactionContext currentTransactionContext;
public EhcacheTransactionObject(LocalTransactionContext currentTransactionContext) {
this.currentTransactionContext = currentTransactionContext;
}
}
}
source code and test case can be found here
This solution has a significant drawback transaction coordinator of ehcache does not support suspend/resume operations so inner transactions (PROPAGATION_REQUIRES_NEW) are not possible. That is why I had to find another one.
Another option is not to use local ehcache transactions at all and use org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager#setTransactionAware which decorates caches to postpone operations until the transaction end. But it has following drawbacks:
Evicted keys stay accessible inside transaction until transaction commit
putIfAbsent operation is not postponed
It was a problem for me, so I implemented this functionality in different way. Check 'me.qnox.springframework.cache.tx.TxAwareCacheManagerProxy', there problems described above was solved, in the same repository
You do not want local transactions, you want XA transactions, which are supported by Ehcache.
Have a look at the documentation for Ehcache 2.10.x or Ehcache 2.8.x.
I am trying to do the following inside a spring bean:
#PostConstruct
public void registerTorchEntityListeners()
{
Session session = entityManager.unwrap(Session.class);
for (EntityType<?> entity : entityManager.getMetamodel().getEntities())
{
if (entity.getJavaType().isAnnotationPresent(TorchEntityListeners.class))
{
TorchEntityListeners annotation = (TorchEntityListeners) entity.getJavaType().getAnnotation(TorchEntityListeners.class);
for (Class listenerClass : annotation.value())
{
Map<String, DescriptorEventListener> map = applicationContext.getBeansOfType(listenerClass);
for (DescriptorEventListener listenerBean : map.values())
{
session.getClassDescriptor(entity.getClass()).getEventManager().addListener(listenerBean);
}
}
}
}
}
The problem is I get the following exception because (I think) I am not in a transaction and therefore do not have a session available to grab the ClassDescriptor so that I can add a listener to a particular entity:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'torchEntityListenerConfigurer': Invocation of init method failed; nested exception is java.lang.IllegalStateException: No transactional EntityManager available
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:133)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:396)
Basically I am trying to do the EclipseLink equivalent of this: http://invariantproperties.com/2013/09/29/spring-injected-beans-in-jpa-entitylisteners/. I would prefer to annotate the entity with the listener rather than doing something like this: Injecting a Spring dependency into a JPA EntityListener.
Thoughts?
Of course I figure it out 30 minutes after I add a bounty :)
I finally got this to work by getting the entityManager from a wired in EntityManagerFactory instead of using: #PersistenceContext to inject it into the TorchEntityListenerConfigurer
Here is the working solution...and it works great!
Here is the config:
<bean id="approvalEntityListener" class="com.prometheus.torchlms.core.activity.approval.ApprovalEntityListener">
<property name="activityRepository" ref="activityRepository" />
<property name="notificationFactory" ref="notificationFactory" />
<property name="notificationService" ref="notificationService" />
</bean>
<bean id="springEntityListenerConfigurer" class="com.prometheus.torchlms.core.SpringEntityListenerConfigurer">
<constructor-arg ref="entityManagerFactory" />
</bean>
Here is where the magic happens (in case this is useful to someone):
public class SpringEntityListenerConfigurer implements ApplicationContextAware
{
private ApplicationContext applicationContext;
private EntityManagerFactory entityManagerFactory;
public SpringEntityListenerConfigurer(EntityManagerFactory entityManagerFactory)
{
this.entityManagerFactory = entityManagerFactory;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException
{
this.applicationContext = applicationContext;
}
#PostConstruct
public void registerTorchEntityListeners()
{
//entityManager.
EntityManager entityManager = entityManagerFactory.createEntityManager();
Session session = entityManager.unwrap(Session.class);
for (EntityType<?> entity : entityManagerFactory.getMetamodel().getEntities())
{
if (entity.getJavaType().isAnnotationPresent(SpringEntityListeners.class))
{
SpringEntityListeners annotation = (SpringEntityListeners) entity.getJavaType().getAnnotation(SpringEntityListeners.class);
for (Class listenerClass : annotation.value())
{
Map<String, DescriptorEventListener> map = applicationContext.getBeansOfType(listenerClass);
for (DescriptorEventListener listenerBean : map.values())
{
ClassDescriptor classDescriptor = session.getClassDescriptor(entity.getJavaType());
if (null != classDescriptor)
{
classDescriptor.getEventManager().addListener(listenerBean);
}
}
}
}
}
}
}
So now I can add my #SpringEntityListeners({ApprovalEntityListener.class}) to any entity I want with any listener that I want and those listeners can be spring beans!
In case it helps here's the annotation:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface SpringEntityListeners
{
Class<?>[] value();
}
In fact you can do your registrations without getting an EntityManager, because you only use it to get a client session, and you only use the client session to register listeners with the server session without any direct interaction with the database nor changing any object.
The EntityManagerFactory is actually an EntityManagerFactoryImpl that can directly expose the ServerSession with unwrap. I had to dig through classes explicitly marked as INTERNAL, to find that, and the ServerSession (also marked as INTERNAL) explicitely states in his javadoc : All changes to objects and the database must be done through a unit of work acquired from the client session, this allows the changes to occur in a transactional object space and under a exclusive database connection.
But for your use case, I think it is correct to use it like that, using the server session only to get access to the Project that actually contains the class descriptors and is a public class in EclipseLink :
public void registerTorchEntityListeners()
{
// no entityManager here and Session is only used to get access to Project
Project proj = entityManagerFactory.unwrap(Session.class).getProject();
for (EntityType<?> entity : entityManagerFactory.getMetamodel().getEntities())
{
if (entity.getJavaType().isAnnotationPresent(SpringEntityListeners.class))
{
SpringEntityListeners annotation = (SpringEntityListeners) entity.getJavaType().getAnnotation(SpringEntityListeners.class);
for (Class listenerClass : annotation.value())
{
Map<String, DescriptorEventListener> map = applicationContext.getBeansOfType(listenerClass);
for (DescriptorEventListener listenerBean : map.values())
{
ClassDescriptor classDescriptor = proj.getClassDescriptor(entity.getJavaType());
if (null != classDescriptor)
{
classDescriptor.getEventManager().addListener(listenerBean);
}
}
}
}
}
}
I am trying to add Repository support to an Eclipselink JPA Spring project. Eclipselink requires LoadTimeWeaving - even though that's not absolutely true I'd later like to get Aspects working as well.
The production application runs under Tomcat, and I might be done by now if I had gone along and not tried to create JUnits. I have a feeling that maybe what I really have is an Eciplse (STS 3.4) problem since it seems to be ignoring my alternate class loader. But it seems so basic that this must work, and that I'm doing something wrong.
I am using exclusively Annotations and Java configuration. The relevant code below.
Configuration
#Configuration
#Profile("data")
#EnableJpaRepositories(basePackages="com.xxx.ieexb.repository",transactionManagerRef="transactionManager",entityManagerFactoryRef="entityManagerFactory")
#ComponentScan(basePackages= {"com.xxx.ieexb.jpa"
,"com.xxx.ieexb.repository"})
#EnableTransactionManagement
#EnableLoadTimeWeaving
#ImportResource("classpath:/properties-config.xml")
public class IeexbDataContextConfig {
#Value("#{ieexbProperties['com.xxx.ieexb.dataSource.Url']}")
public String dataSourceUrl;
#Value("#{ieexbProperties['com.xxx.ieexb.dataSource.Username']}")
public String dataSourceUsername;
#Value("#{ieexbProperties['com.xxx.ieexb.dataSource.Password']}")
public String dataSourcePassword;
#Value("#{ieexbProperties['com.xxx.ieexb.persistenceUnitName']}")
public String persistenceUnitName;
#Autowired
EntityManagerFactory entityManagerFactory;
#Bean()
public DriverManagerDataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.springframework.jdbc.datasource.DriverManagerDataSource");
dataSource.setUrl(dataSourceUrl);
dataSource.setUsername(dataSourceUsername);
dataSource.setPassword(dataSourcePassword);
return dataSource;
}
#Bean()
EclipseLinkJpaVendorAdapter eclipseLinkJpaVendorAdapter() {
EclipseLinkJpaVendorAdapter eclipseLinkJpaVendorAdapter = new EclipseLinkJpaVendorAdapter();
eclipseLinkJpaVendorAdapter.setShowSql(true);
eclipseLinkJpaVendorAdapter.setGenerateDdl(false);
eclipseLinkJpaVendorAdapter.setDatabasePlatform("org.eclipse.persistence.platform.database.OraclePlatform");
return eclipseLinkJpaVendorAdapter;
}
#Bean()
EclipseLinkJpaDialect jpaDialect() {
EclipseLinkJpaDialect jpaDialect = new EclipseLinkJpaDialect();
return jpaDialect;
}
#Bean()
public FactoryBean<EntityManagerFactory> entityManagerFactory() {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
//TODO Does this #Configuration do away with need for persistence.xml?
//emf.setPersistenceXmlLocation("classpath:persistence.xml");
emf.setPersistenceUnitName(persistenceUnitName);
emf.setDataSource(dataSource());
emf.setLoadTimeWeaver(loadTimeWeaver());
emf.setJpaDialect(new EclipseLinkJpaDialect());
emf.setJpaVendorAdapter(eclipseLinkJpaVendorAdapter());
//emf.setPersistenceProvider(persistenceProvider());
return emf;
}
#Bean()
public LoadTimeWeaver loadTimeWeaver() {
LoadTimeWeaver loadTimeWeaver = new ReflectiveLoadTimeWeaver();
return loadTimeWeaver;
}
}
The dead simple Entity (with some of the truly boring columns removed):
#Entity
#Cacheable(false)
#Table(name="PENDING_QUEUE"
, uniqueConstraints = #UniqueConstraint(columnNames="IEEXB_ID,QUEUE_TIMESTAMP")
)
public class PendingQueue implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
#AttributeOverrides( {
#AttributeOverride(name="ieexbId", column=#Column(name="IEEXB_ID", nullable=false) ),
#AttributeOverride(name="queueTimestamp", column=#Column(name="QUEUE_TIMESTAMP", nullable=false) ) } )
private PendingQueueId id;
#Column(name="IE_USER", nullable=false, length=21)
private String ieUser;
#Column(name="COMMAND_TYPE", nullable=false, length=3)
private String commandType;
public PendingQueue() {
;
}
public PendingQueue(PendingQueueId id, String ieUser, String commandType) {
super();
this.id = id;
this.ieUser = ieUser;
this.commandType = commandType;
}
public PendingQueueId getId() {
return id;
}
public void setId(PendingQueueId id) {
this.id = id;
}
public String getIeUser() {
return ieUser;
}
public void setIeUser(String ieUser) {
this.ieUser = ieUser;
}
public String getCommandType() {
return commandType;
}
public void setCommandType(String commandType) {
this.commandType = commandType;
}
....
}
The Repository of course:
#Repository
public interface PendingQueueRepository extends CrudRepository<PendingQueue, PendingQueueId> {
List<PendingQueue> findByIeUser(String ieUser);
}
And finally the JUnit:
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles(profiles = {"data"})
#ContextConfiguration(classes = IeexbDataContextConfig.class, loader = AnnotationConfigContextLoader.class)
public class TestPendingQueue {
#Autowired
PendingQueueRepository pendingQueueRepository;
#Test
public void testFindByIeUser() {
List<PendingQueue> results = pendingQueueRepository.findByIeUser("JPA.XXX.BOB1");
System.out.println("Found Items:" + results.size());
System.out.println("First item is:" + results.get(0));
}
}
I am trying to run the JUnit with this VM ARG:
-javaagent:C:\Users\Terry\.m2\repository\org\springframework\spring-agent\2.5.6.SEC03\spring-agent-2.5.6.SEC03.jar
I also tried adding the AspectJ weaver, but it didn't help
-javaagent:C:\Users\Terry\.m2\repository\org\aspectj\aspectjweaver\1.8.0\aspectjweaver-1.8.0.jar
I have not tried the Spring Tomcat weaver but that doesn't seem like the right direction. I've read people then had problems with JUnit finding class files.
Without pasting in the rather huge stack trace it all boils down to this:
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.instrument.classloading.LoadTimeWeaver
com.xxx.ieexb.config.IeexbDataContextConfig.loadTimeWeaver()] threw exception; nested exception is java.lang.IllegalStateException: ClassLoader [sun.misc.Launcher$AppClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method.
Which is of course true. That classloader doesn't support weaving. But I have tried very very hard to not use that loader. Any help appreciated
I have a similar setup and adding the following VM args for unit tests works for me:
-javaagent:/path/to/spring-instrument-4.0.0.RELEASE.jar -javaagent:/path/to/aspectjweaver-1.8.0.jar
It appears the problem was that in the #Configuration class I included a definition for a LoadTimeWeaver bean. I also set that value inside the EntityManagerFactory constructor. By removing that I no longer get the runtime error during spring container startup.
Looking at the Spring console it says my Entity Beans were transformed (woven) so perhaps Lazy loading would still work - I don't have any DB associations to try it on in this particular project.
One other note is not only is persistence.xml NOT required it is not allowed. Eclipselink was hunting down another copy of persistence.xml I didn't know about and that was causing the Entity backing my Repository to not get discovered.
But right now I believe the example I've posted (minus the loadTimeWeaving bean) is, remarkably, one of the best, or at least most complete, examples out there - who'd have expected that!
i couldn't get the above to work. amazon aws doesn't let me put the instrumentation jar in tomcat/lib folder so i could not use -javaagent approach (believe me i tried!). i had to switch to eclipselink static weaving
it's not too hard, a persistence.xml file is required but if you're already using annotated configuration it can be as short as:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="ADD_NAME_HERE">
<!--this is necessary for the eclipselink static weaving maven plugin-->
<!--this setting auto-detects entities in the project-->
<exclude-unlisted-classes>false</exclude-unlisted-classes>
</persistence-unit>
</persistence>
but note that it MUST be in your project that contains the entity classes. i made the mistake of dropping the persistence.xml file and the maven plugin in the pom.xml file into my website project not my domain project.
If one needs to set -javaagent by maven, it can do it like this:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<argLine>
-javaagent:"${settings.localRepository}/org/springframework/spring-instrument/${org.springframework.version}/spring-instrument-${org.springframework.version}.jar"
</argLine>
</configuration>
</plugin>
</plugins>
(just set property for ${org.springframework.version} or replace for corresponding version)
This way it's associated with your project, and not with your jvm or webserver
I have an issue with an injected EntityManager in my MessageDriven Bean that use spring bean as services (the bootstrap is done with the SpringBeanAutowiringInterceptor.
Here is the code :
#MessageDriven(name = "ProcessMDB")
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class ProcessMDB implements MessageListener {
#Autowired
private ProcessService processService;
#Override
public void onMessage(Message message) {
try {
id = message.getLongProperty("ID");
processService.process(id);
} catch (Exception e) {
// Handle error.
}
}
The process service has a DAO where the EntityManager is injected with the annotation #PersistentContext...
The problem is that if a JPA error occurs in the processService, it may occur during the entityManager.flush() call... so the try catch block is gone and the //Handle error stuff is not done.
So I tried to add manually the flush.
#MessageDriven(name = "ProcessMDB")
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class ProcessMDB implements MessageListener {
#Autowired
private ProcessService processService;
#PersistenceContext
private EntityManager em;
#Override
public void onMessage(Message message) {
try {
id = message.getLongProperty("ID");
processService.process(id);
em.flush();
} catch (Exception e) {
// Handle error.
}
}
But it seems that the flush has no effect.
I've try to add the em.flush in the underlying DAO (just after the persist for instance) and it works! The exception is well raised and the catch block is executed. But it doesn't work if I put the em.flush() at the MessageDrivenBean level.
I think that it's transaction manager problem... The entitymanager in spring beans is not in the same tx than the injected entity manager in my ejb.
If I make em.find in the onMessage() method, the fetched object holds old values (the one in the database), not values that are changed in the service method.
I've configured my database as followed :
<jee:jndi-lookup id="emf" jndi-name="persistence/PUnit" />
and my tx manager as followed :
<tx:annotation-driven/>
<tx:jta-transaction-manager />
What do I wrong?
Can someonee help me?
Thanks
Stéphane
You have injected EntityManager in ProcessMDB, but the object is being persisted in ProcessService.
Now, how can any operation in ProcessMDB can affect ProcessService, both will have probably their own individual EntityManager.
Scope of PersistenceContext is upto associated EntityManager. The object will be in the context of ProcessService & not in ProcessMDB, therefore calling flush on later will have no effect & this is expected behaviour.