GlassFish 4 (actually its JPA implementation, i.e. EclipseLink) fails to lazy load a #ManyToOne JPA relation from our Java EE 7 application. Default/eager loading is ok, but not lazy loading.
The relation in the 'Student' entity is:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "addr_id")
private Address address;
The (simplified) persistence.xml looks like:
<persistence 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"
version="2.1">
<persistence-unit name="foo-PU" transaction-type="JTA">
<jta-data-source>jdbc/foo-DS</jta-data-source>
<class>foo.domain.Student</class>
<class>foo.domain.Address</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="eclipselink.target-database" value="PostgreSQL"/>
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
</persistence>
The application uses several API: PrimeFaces, JSF 2.2, CDI 1.1, JPA 2.1.
Also note that the EntityManager are not obtained by injection into session EJB, but manually created using Persistence.createEntityManagerFactory(...) then emf.createEntityManager(...).
The error message is:
WARNING: Reverting the lazy setting on the OneToOne or ManyToOne attribute [address] for the entity class [class foo.domain.Student] since weaving was not enabled or did not occur.
My understanding is that, for some reason, the dynamic weaving of entities is not enabled. For a Java EE application it should be, as suggested by http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving.
For the record, if we try to force the weaving using this:
<property name="eclipselink.weaving" value="true"/>
in the persistence.xml, then we get another error message:
SEVERE: Error Rendering View[/student/studentList.xhtml]
javax.el.ELException: /student/studentList.xhtml #24,81 value="#{studentController.selectedCode}": Exception [EclipseLink-30005] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.PersistenceUnitLoadingException
Exception Description: An exception was thrown while searching for persistence archives with ClassLoader: WebappClassLoader (delegate=true; repositories=WEB-INF/classes/)
Internal Exception: javax.persistence.PersistenceException: Exception [EclipseLink-28022] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Value [true] for the property [eclipselink.weaving] is incorrect when global instrumentation is null, value should either be null, false, or static.
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:114)
at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194)
at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:182)
at javax.faces.component.UIOutput.getValue(UIOutput.java:174)
at javax.faces.component.UIInput.getValue(UIInput.java:291)
at com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getValue(HtmlBasicInputRenderer.java:205)
(...)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
Any idea how to fix this lazy-loading issue? Why is the dynamic weaving not enabled by default ?
Thanks.
If you set eclipselink.weaving to true it means that you want to weave an entity classes dynamically. To make this work you need to run a jvm with a proper javaagent. First download an agent
wget -O /tmp/eclipselink.jar \
https://repo1.maven.org/maven2/org/eclipse/persistence/eclipselink/2.7.7/eclipselink-2.7.7.jar
and then run your app using following snippet
java -javaagent:/tmp/eclipselink.jar ....
But if you set eclipselink.weaving to static then you inform jpa that you want to weave the entity classes statically. Of course you have to trigger the waving by your own for example using this maven plugin https://github.com/craigday/eclipselink-staticweave-maven-plugin
Related
Exception is thrown when trying to Insert/Update/Delete with executeUpdate(). Select query works fine.I have tried all the suggestions from previous similar error mentioned in stack-overflow. Appreciate any guidance.
Environment : Websphere Liberty : 17.0.0.2, Eclipselink 2.6.4, JPA 2.1
Features enabled on Liberty server
<featureManager>
<feature>adminCenter-1.0</feature>
<feature>beanValidation-1.1</feature>
<feature>cdi-1.2</feature>
<feature>concurrent-1.0</feature>
<feature>ejbLite-3.2</feature>
<feature>el-3.0</feature>
<feature>jsf-2.2</feature>
<feature>jsp-2.3</feature>
<feature>localConnector-1.0</feature>
<feature>servlet-3.1</feature>
<feature>jpa-2.1</feature>
<!--The following features are available in Liberty base and above. -->
<feature>jaxb-2.2</feature>
</featureManager>
Peristence.xml
<?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="BlueeCron" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/BlueeUPMDataSource</jta-data-source>
<mapping-file>META-INF/queries.xml</mapping-file>
<class>com.bcbsnc.providers.models.BlueEReqst</class>
<class>com.bcbsnc.providers.models.BlueERespn</class>
<properties>
<property name="eclipselink.logging.level" value="ALL" />
<property name="eclipselink.logging.level.sql" value="FINE" />
<property name="eclipselink.logging.parameters" value="true" />
</properties>
</persistence-unit>
#Stateless
#Repository("emJPADao")
public class JPADao {
EntityManager entityManager = Persistence.createEntityManagerFactory("BlueeCron").createEntityManager();
public Integer purgeBxTables() {
Integer rowsDeleted = 0;
try {
Integer noOfDays = Integer.parseInt(this.getConfigurationData("PurgeBXTablesPeriod"));
rowsDeleted = entityManager.createNamedQuery("PURGE_BX_TABLES").setParameter("noOfDays", getTimeStamp(noOfDays, false)).executeUpdate();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(entityManager.isOpen())
entityManager.close();
}
}
}
Logs at server startup
Launching defaultServer (WebSphere Application Server 17.0.0.2/wlp-1.0.17.cl170220170523-1818) on IBM J9 VM, version pwa6480sr4fp5-20170421_01 (SR4 FP5) (en_US)
[AUDIT ] CWWKF0012I: The server installed the following features: [jsp-2.3, ejbLite-3.2, servlet-3.1, jsf-2.2, beanValidation-1.1, ssl-1.0, jndi-1.0, jca-1.7, jdbc-4.2, localConnector-1.0, appSecurity-2.0, jaxrs-2.0, restConnector-1.0, el-3.0, jaxrsClient-2.0, concurrent-1.0, wmqJmsClient-2.0, jaxb-2.2, json-1.0, jpaContainer-2.1, adminCenter-1.0, cdi-1.2, distributedMap-1.0, jpa-2.1].
[AUDIT ] CWWKF0011I: The server defaultServer is ready to run a smarter planet.
[EL Info]: server: 2017-10-19 10:23:13.215--ServerSession(1864654006)--Detected server platform: org.eclipse.persistence.platform.server.was.WebSphere_Liberty_Platform.
S
Exception :
[err] javax.persistence.TransactionRequiredException:
Exception Description: No externally managed transaction is currently active for this thread
[err] at org.eclipse.persistence.internal.jpa.transaction.JTATransactionWrapper.throwCheckTransactionFailedException(JTATransactionWrapper.java:94)
[err] at org.eclipse.persistence.internal.jpa.transaction.JTATransactionWrapper.checkForTransaction(JTATransactionWrapper.java:54)
[err] at org.eclipse.persistence.internal.jpa.EntityManagerImpl.checkForTransaction(EntityManagerImpl.java:2054)
[err] at org.eclipse.persistence.internal.jpa.QueryImpl.executeUpdate(QueryImpl.java:291)
[err] at com.bcbsnc.providers.dao.JPADao.purgeBxTables(JPADao.java:49)
The executeUpdate() method requires for the EntityManager to be enlisted with a transaction - a global transaction in this case since you have defined a JTA-type persistence unit. You have chosen to use JPA's JSE bootstrapping approach (using Persistence.createEntityManagerFactory() instead of injection via #PersistenceContext or #PersistenceUnit) -- while I don't endorse using the JSE bootstrapping method in an EE application, it's not dis-allowed by the spec.
However, I believe the problem you are hitting is the fact that what you have effectively here is an application-managed persistence context, and thus your application is responsible for its enlistment with the global transaction (which would have been begun automatically by the EJB container when purgeBxTables() was called, as I do not see any annotations declaring it as a bean-managed-transaction session bean) which requires calling EntityMangager.joinTransaction().
An application-managed EntityManager will only join the global transaction automatically when the EntityManager is first created. Which is not the case for your application since the EntityManager is created when the bean class is constructed. Otherwise, the joinTransaction() method invocation is required in order for an EntityManager to join a new transaction.
Your application will need to call em.joinTransaction() before you call executeUpdate().
Using a container managed persistence context (using #PersistenceContext to inject an EntityManager) would have had the EntityManager automatically join the global transaction (unless you override the default Transaction SynchronizationType to UNSYNCHRONIZED.)
I have problem with configuring JPA in Websphere Liberty Profile. EclipseLink which is default provider in WAS with feature jpa-2.1 don't read the properties from created in server.xml DataSource. I've tried to get connection from this data source without JPA and this connection was succesfull, i had access to database. But when i use JPA and then create EntityManagerFactory from my PerstistenceUnit i get exception which in my opinion means that i didn't give required parameters such as url, username and password. I tested that WAS recognize EclipseLink provider, but now i don't know what can I do with this problem. Google haven't helped me.
Persistence.xml
<persistence version="1.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_1_0.xsd">
<persistence-unit name="test-unit" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>java:comp/env/jdbc/PostgreDS</jta-data-source>
<properties>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
<property name="eclipselink.ddl-generation.output-mode"
value="database" />
</properties>
</persistence-unit>
server.xml(only part with my setting of JDBC and DS)
<jdbcDriver id="myJDBCDriver" libraryRef="JDBCLib" javax.sql.XADataSource="org.postgresql.xa.PGXADataSource" >
</jdbcDriver>
<library id="JDBCLib" name="PostgreLib">
<file name="/home/hubert/JavaLibs/postgresql-9.4-1206-jdbc41.jar" id="JDBC_JAR"></file>
</library>
<dataSource id="PostrgreConnection" jdbcDriverRef="myJDBCDriver" jndiName="jdbc/PostgreDS" type="javax.sql.XADataSource">
<properties URL="jdbc:postgresql://localhost/GotSpotDB" databaseName="GotSpotDB" password="testtest" portNumber="5432" serverName="localhost" user="GotSpotAdmin"/>
</dataSource>
Logs
[ERROR ] CWWJP9992E: Exception [EclipseLink-4021] (Eclipse Persistence Services - 2.6.1.WAS-v20160106-a06c2b3): org.eclipse.persistence.exceptions.DatabaseException
Exception Description: Unable to acquire a connection from driver [null], user [null] and URL [null]. Verify that you have set the expected driver class and URL. Check your login, persistence.xml or sessions.xml resource. The jdbc.driver property should be set to a class that is compatible with your database platform
[ERROR ] SRVE0777E: Exception thrown by application class 'org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy:837'
javax.persistence.PersistenceException: Exception [EclipseLink-4021] (Eclipse Persistence Services - 2.6.1.WAS-v20160106-a06c2b3): org.eclipse.persistence.exceptions.DatabaseException
Exception Description: Unable to acquire a connection from driver [null], user [null] and URL [null]. Verify that you have set the expected driver class and URL. Check your login, persistence.xml or sessions.xml resource. The jdbc.driver property should be set to a class that is compatible with your database platform
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:837)
at [internal classes]
at pl.almost.done.TestServlet.doGet(TestServlet.java:52)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
at [internal classes]
Caused by: Exception [EclipseLink-4021] (Eclipse Persistence Services - 2.6.1.WAS-v20160106-a06c2b3): org.eclipse.persistence.exceptions.DatabaseException
Exception Description: Unable to acquire a connection from driver [null], user [null] and URL [null]. Verify that you have set the expected driver class and URL. Check your login, persistence.xml or sessions.xml resource. The jdbc.driver property should be set to a class that is compatible with your database platform
at org.eclipse.persistence.exceptions.DatabaseException.unableToAcquireConnectionFromDriverException(DatabaseException.java:383)
... 4 more
I have inherited a legacy application that initially was built with WebSphere 6.1 and then was migrated to WebSphere 8.0 running with JPA 2.0 and openJPA without issues. We are migrating to WebSphere Liberty for strategic reasons. We first tested on WebSphere Classic 8.5.5.8 and JPA and the entity manger has no issues there. However, on Liberty 8.5.5.8 I get the following exception:
javax.ejb.EJBException: The java:comp/env/com.xxx.xxxx.service.CHServiceBean/em reference of type javax.persistence.EntityManager for the CHServiceBean component in the CHServiceEJB.jar module of the CHServiceEAR application cannot be resolved.
at com.ibm.wsspi.injectionengine.InjectionBinding.getInjectionObject(InjectionBinding.java:1493)
.....
[err] Caused by:
[err] javax.ejb.EJBException: The java:comp/env/com.xxxx.xxxx.service.CHServiceBean/em reference of type javax.persistence.EntityManager for the CHServiceBean component in the CHServiceEJB.jar module of the CHServiceEAR application cannot be resolved.
[err] at com.ibm.wsspi.injectionengine.InjectionBinding.getInjectionObject(InjectionBinding.java:1493)
[err] at [internal classes]
I had another EJB injection issue that was resolved through configuration of the binding files, however I am unable to resolve this issue. I have two applications that each have their own EAR files but both run in the same Liberty JVM. Application A runs the front end/UI logic while Application B is the back-end EJB / JPA interfaces. In the project facets the JPA application is set to 2.0 (I wanted 2.1 but based on another thread JPA 2.0 and EJB 3.1 are as high as I can go at the moment...See my other thread topic here -->Eclipse Juno and JPA 2.1 support).
Here is my server.xml file:
<server description="new server">
<!-- Enable features -->
<featureManager>
<feature>javaee-7.0</feature>
<feature>localConnector-1.0</feature>
<feature>distributedMap-1.0</feature>
<feature>adminCenter-1.0</feature>
<feature>ssl-1.0</feature>
<feature>usr:webCacheMonitor-1.0</feature>
<feature>webCache-1.0</feature>
<feature>ldapRegistry-3.0</feature>
</featureManager>
<!-- Admin Center Config Start -->
<!-- To access this server from a remote client add a host attribute to the following element, e.g. host="*" -->
<httpEndpoint host="*" httpPort="9080" httpsPort="9443" id="defaultHttpEndpoint"/>
<keyStore id="defaultKeyStore" password="xxxxxx"/>
<basicRegistry id="basic">
<user name="admin" password="xxxxx"/>
<user name="nonadmin" password="xxxxxx"/>
</basicRegistry>
<administrator-role>
<user>admin</user>
</administrator-role>
<remoteFileAccess>
<writeDir>${server.config.dir}</writeDir>
</remoteFileAccess>
<!-- Automatically expand WAR files and EAR files -->
<applicationManager autoExpand="true"/>
<applicationMonitor updateTrigger="mbean"/>
<enterpriseApplication id="CHNewCHRDMEAR" location="CHNewCHRDMEAR.ear" name="CHNewCHRDMEAR">
<application-bnd>
<security-role name="AllAuthenticated">
<special-subject type="ALL_AUTHENTICATED_USERS"/>
</security-role>
</application-bnd>
</enterpriseApplication>
<enterpriseApplication id="CHServiceEAR" location="CHServiceEAR.ear" name="CHServiceEAR"/>
<!-- JAAS Authentication Alias (Global) Config -->
<authData id="dbUser" password="{xor}MzhmJT06ajI=" user="dbUser"/>
<!-- JDBC Driver and Datasource Config -->
<library id="DB2JCC4Lib">
<fileset dir="C:\DB2\Jars" includes="db2jcc4.jar db2jcc_license_cisuz.jar"/>
</library>
<dataSource containerAuthDataRef="dbUser" id="CHTEST2" jndiName="jdbc/nextgen" type="javax.sql.XADataSource">
<jdbcDriver libraryRef="DB2JCC4Lib"/>
<properties.db2.jcc databaseName="CHTEST2" password="{xor}MzhmJT06ajI=" portNumber="60112" serverName="server.com" sslConnection="false" user="dbUser"/>
<containerAuthData password="{xor}MzhmJT06ajI=" user="dbUser"/>
</dataSource>
<dataSource id="CHTEST2_RO" jndiName="jdbc/nextgen_RO" type="javax.sql.XADataSource">
<jdbcDriver libraryRef="DB2JCC4Lib"/>
<properties.db2.jcc databaseName="CHTEST2" password="{xor}MzhmJT06ajI=" portNumber="60112" serverName="server.com" sslConnection="false" user="dbUser"/>
<containerAuthData password="{xor}MzhmJT06ajI=" user="dbUser"/>
</dataSource>
<!-- More in file, but no included...-->
</server>
Here is my persistence.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<persistence 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"
version="2.0">
<persistence-unit name="CHService" transaction-type="JTA">
<jta-data-source>jdbc/nextgen</jta-data-source>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="openjpa.jdbc.TransactionIsolation" value="read-uncommitted" /></properties></persistence-unit>
<persistence-unit name="CHServiceRO" transaction-type="JTA">
<jta-data-source>jdbc/nextgen_RO</jta-data-source>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="openjpa.jdbc.TransactionIsolation" value="read-uncommitted" />
</properties>
</persistence-unit>
</persistence>
I *believe that we are relying solely on injection to get the context for JPA jndi lookups but that is because I don't see in our code any call to an initial context for any JPA specific JNDI names. Below are my two anotated session beans from the EJB project:
a. The CHService Bean:
#Stateless
#TransactionManagement(TransactionManagementType.CONTAINER)
#Local({ CHServiceLocal.class })
#Remote({ CHServiceRemote.class })
#Interceptors({ CHServiceLog.class })
#Resources({
#Resource(name = "jdbc/nextgen", mappedName = "jdbc/nextgen", authenticationType = AuthenticationType.APPLICATION, shareable = true, type = javax.sql.DataSource.class),
#Resource(name = "services/cache/CHBluepages", mappedName = "services/cache/CHBluepages", authenticationType = AuthenticationType.APPLICATION, shareable = true, type = com.ibm.websphere.cache.DistributedMap.class),
#Resource(name = "services/cache/CHGeneric", mappedName = "services/cache/CHGeneric", authenticationType = AuthenticationType.APPLICATION, shareable = true, type = com.ibm.websphere.cache.DistributedMap.class) })
public class CHServiceBean extends AbstractCHServiceImpl implements
CHService {
#PersistenceContext(unitName = "CHService")
private EntityManager em;
b. The CHServiceRO bean:
#Stateless
#TransactionManagement(TransactionManagementType.CONTAINER)
#Local({CHServiceLocalRO.class})
#Remote({CHServiceRemoteRO.class})
#Interceptors({CHServiceROLog.class})
#Resources({
#Resource(name="jdbc/nextgen_RO", mappedName="jdbc/nextgen_RO", authenticationType=AuthenticationType.APPLICATION, shareable=true, type=javax.sql.DataSource.class),
#Resource(name="jdbc/nextgen", mappedName="jdbc/nextgen", authenticationType=AuthenticationType.APPLICATION, shareable=true, type=javax.sql.DataSource.class),
#Resource(name="services/cache/CHBluepages", mappedName="services/cache/CHBluepages", authenticationType=AuthenticationType.APPLICATION, shareable=true, type=com.ibm.websphere.cache.DistributedMap.class),
#Resource(name="services/cache/CHGeneric", mappedName="services/cache/CHGeneric", authenticationType=AuthenticationType.APPLICATION, shareable=true, type=com.ibm.websphere.cache.DistributedMap.class)
})
public class CHServiceBeanRO implements CHServiceRO {
#PersistenceContext (unitName="CHServiceRO") private EntityManager em;
private CHServiceBase ch;
#PostConstruct
private void init() { ch = new CHServiceBase(em); }
Here is a snippet from the Web.xml of the front-end application calling the JPA application:
<resource-ref id="ResourceRef_1436377001246">
<res-ref-name>jdbc/nextgen</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Application</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
<resource-ref id="ResourceRef_1436377001247">
<res-ref-name>jdbc/nextgen_RO</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Application</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
Based on the post from Gas on this topic: java.lang.ClassCastException,Getting Entitymanager Via JNDI Lookup
I also tried updating the web.xml with the following entries:
<persistence-unit-ref>
<persistence-unit-ref-name>chJPA</persistence-unit-ref-name>
<persistence-unit-name>CHService</persistence-unit-name>
</persistence-unit-ref>
<persistence-unit-ref>
<persistence-unit-ref-name>chJPA_RO</persistence-unit-ref-name>
<persistence-unit-name>CHServiceRO</persistence-unit-name>
</persistence-unit-ref>
and the Bean code with:
#PersistenceContext(name = "chJPA", unitName = "CHService")
and
#PersistenceContext (name="chJPA_RO", unitName="CHServiceRO")
Got the same error just with a different jndi name, ie The java:comp/env/chJPA reference of type javax.persistence.EntityManager for the CHServiceBean com.......etc etc.
Lastly, per this post: Error while accessing EntityManager - openjpa - WAS liberty profile
It seems that maybe I can't have the full JavaEE 7 feature and run JPA 2.0? Please advise!
As in the post you are referring to - you cannot have <feature>javaee-7.0</feature> together with JPA 2.0, as it enables 2.1, thats why you have conflicts.
So you have 2 options:
either use Java EE7 and JPA 2.1
or just enable required Java EE 6 features and then use JPA 2.0
Since you are migrating from WAS 8.0, which doesn't support Java EE7 for now, easier choice might be to use the second option.
So try to remove javee-7.0 feature, and add ejbLite-3.1 and jpa-2.0 and whatever you need more.
You are correct that you cannot have javaee-7.0 and the JPA 2.0 feature, as it enables the JPA 2.1 feature. So the answer Gas gave is correct.
I just wanted to point out since you said that you do want to go to JPA 2.1 eventually, once you work out your eclipse issues, that you should use the WebSphere Application Server Migration Toolkit to identify application changes needed when migrating from JPA 2.0 to JPA 2.1. The Liberty JPA 2.0 implementation is built on OpenJPA, whereas the JPA 2.1 implemtation is built on EclipseLink. The migration toolkit is downloadable for free on wasdev: https://developer.ibm.com/wasdev/downloads/#asset/tools-WebSphere_Application_Server_Migration_Toolkit
I need to detach some entity objects from the database to make them unmanaged. I use EclipseLink persistence provider, which method EntityManager.detach() is exactly one I need. The problem is that JBoss throws at runtime following exception (when execution passes to detach()):
javax.ejb.EJBTransactionRolledbackException: Unexpected Error
java.lang.NoSuchMethodError: javax.persistence.EntityManager.detach(Ljava/lang/Object;)V
Other methods like persist, merge, find work fine. I tried Hibernate and know that its Session provides a special method evict(), which detaches entity, but EclipseLink has no such method.
Example of using detach():
#PersistenceContext(unitName="Course7-ejbPU")
protected EntityManager manager;
(...)
Query query;
List<Message> resultList;
query = manager.createNamedQuery("Message.getUserInputMessageList");
query.setParameter("login", login);
query.setMaxResults(5);
resultList = query.getResultList();
for (Message message : resultList)
if (message.getContent().length() > 50)
{
manager.detach(message);
message.setContent(message.getContent().substring(0, 50) + "...");
}
Persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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="Course7-ejbPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>java:/Course7ds</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.target-server" value="JBoss"/>
</properties>
</persistence-unit>
</persistence>
Library with provider data is included into ear archive.
EclipseLink version is 2.2.0 (tested with 2.3.2 - no difference), JBoss server version 5.1.0. Any suggestions will be appreciated.
This exception shows that you're not using JPA2, but JPA1. You should probably use a more recent version of JBoss, that ships with JPA2.
You compiled your code with JPA 2.0 classes, but you run it with JPA 1.0. This is why the JVM doesn't find the detach method.
In reaction to your comment: no, the detach method is not useless for JPA 1.0 user: it's just it has not been created yet. You can however erase all the L1 cache by calling clean() on the entitymanager, which will detach all your managed entities...
You can still be able to detach an entity by using persistence provider specific code.
It is not because the entity manager does not provide a function yet, that the jpa providers hasn't implemented it yet.
If you can couple a little bit your code to your jpa provider:
You can call the em.getDelegate() method that will return you an EclipseLink entity manager implementation (check in debug the returned value and cast it) which may perhaps give you the possibility to detach your entity.
The method may not be named detach() -> for Hibernate it's evict().
I have a perfectly working application client deployed to a GlassFish v2 server inside an ear with some EJBs, Entities, etc. I'm using eclipselink.
Currently I have in my persistence.xml:
<persistence-unit name="mysource">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/mysource</jta-data-source>
<class>entities.one</class>
<class>entities.two</class>
...
<properties>
<property name="eclipselink.target-server" value="SunAS9"/>
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
And this works fine when I inject the EntityManager into the EJB:
#PersistenceContext(unitName="mysource")
private EntityManager em;
Now I have a requirement to dynamically switch persistence units/databases.
I figure I can get an EntityManager programatically:
em = Persistence.createEntityManagerFactory("mysource").createEntityManager();
but I get the following error:
Unable to acquire a connection from driver [null], user [null] and URL [null]
Even "overriding" javax.persistence.jtaDataSource" to "jdbc/mysource" in a Map and calling createEntityManagerFactory("mysource", map) doesn't make a difference.
What am I missing?
You are trying to circumvent the container with creating an entity manager programmatically and this means you'll most probably create a non-JTA data source (as it's outside the container, the transaction type should be RESOURCE_LOCAL), thus your original config is useless.
Try injecting an entity manager with a different unitName property or create a RESOURCE_LOCAL transaction type persistence unit.