JPA + Hibernate + EHCache, unexpected behavior - java

I'm trying to implement EHCache into my working prototype, where I have a javax.persistence.Entity representing a table on my database (MySQL, mysql-connector-java-5.1.20.jar), which be provided as XML to the consumers.
The issue I'm facing is that seems Hibernate still retrieving the data from the database, even when EHCache stores the query result on memory.
I'm using the EHCache monitor to see the count of items in memory, and changing the data directly on database before the cache expires to know if the cached data is actually used.
I been looking for a replication for this issue without succeed, so maybe I'm missing something (I just geting into the java world).
My files
pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.3.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.1.4.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.1.4.Final</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>org.terracotta</groupId>
<artifactId>ehcache-probe</artifactId>
<version>1.0.2</version>
</dependency>
Entity class
package myPrototype.entities
import javax.persistence.Cacheable;
import javax.persistence.Entity;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
#Entity #Cacheable
#Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
#Table(name = "Cars")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Cars.findAll", query = "SELECT d FROM Cars d"),
[...]
public class Cars implements Serializable {
private static final long serialVersionUID = 1L;
#Basic(optional = false)
#NotNull
#Column(name = "id")
#ReferenceField
private int id;
[...]
ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<cache name="myPrototype.entities.Cars"
maxElementsInMemory="500"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="60"
timeToLiveSeconds="120" />
</ehcache>
* I tried setting eternal="true", but the result still the same
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="MyPrototype" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:app/jdbc/mysqlserver/prototype</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<properties>
<!-- property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"/ -->
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory" />
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.cache.region_prefix" value=""/>
</properties>
</persistence-unit>
</persistence>
* I tried switching between SingletonEhCacheRegionFactory and EhCacheRegionFactory
EJB
import myPrototype.entities.Cars
import java.util.Date;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
#Stateless
public class CarsEJB {
#PersistenceContext(unitName="MyPrototype")
private EntityManager em;
#Override
public List<Cars> getCars() {
return (List<Cars>)em.createNamedQuery("Cars.findAll").setMaxResults(200).getResultList();
}
}
* Added to clarify how I run the query
Like I said, I can see a count of items in memory through EHCache monitor, so I noted the following:
- The ehcache configuration is property loaded elements are expiring
- The elements expiration not being reseted when the query runs while they still alive (they expired N seconds after the first query).
Again; I'm quite a newbie with java, so asume I could be missing basic concepts.
Thanks for reading!

Hibernate will never execute queries on your cache. What it can do is execute a query on the database, cache the results, and return these cached results the next time you execute the same query, with the same parameters. But to do that, the query, each time it's executed, must be cacheable.
WIth the JPA API, this is done using query hints, directly on the named query definition, or each time you create a query:
#NamedQuery(name = "Cars.findAll",
query = "SELECT d FROM Cars d",
hints = {#QueryHint(name = "org.hibernate.cacheable", value = "true")})
Now that the query is cacheable, Hibernate will load the IDs of the cars from the database the first time this query is executed, and from the query cache afterwards. Then the corresponding cars themselves will be loaded from the entity cache.

Related

While using OneToMany tags .. No Persistence provider for EntityManager - Hibernate JPA

Well i've benn looking for this problem wasting so much time, so i'm here.
import javax.persistence.*;
#Entity
#Table(name = "secretario")
public class Secretario {
#Id
#GeneratedValue
private long codigoS;
#Column
private String nombre;
#ManyToOne
#JoinColumn(name = "codigoE")
private Empleado e;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
#Entity
#Table
public class Empleado implements Serializable {
private static final long serialVersionUID = 1l;
#Id
#Column
#GeneratedValue
private long codigoE;
#Column
private String apellido;
#Column
private String nombre;
#OneToMany(mappedBy = "e")
private ArrayList<Secretario> secretario;
When i use te OneToMany and ManyToOne tags i got this exception and i dont why... or how ...
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL8Dialect
Exception in thread "main" javax.persistence.PersistenceException: No Persistence provider for EntityManager named Persistencia
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:85)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
at tests.TestEmpleados.main(TestEmpleados.java:22)
here is my persistence config
<?xml version="1.0" encoding="UTF-8" ?>
<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" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="Persistencia">
<!-- <description>
Persistence unit for the JPA tutorial of the Hibernate Getting Started Guide
</description>-->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!-- Representar clases -->
<class>model.Empleado</class>
<class>model.Secretario</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/hibernate"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value=""/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL8Dialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
And my maven config
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>Hibernate</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.3.1.Final</version>
</dependency>
<!--<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.3.1.Final</version>
</dependency>-->
<!-- https://mvnrepository.com/artifact/javax.persistence/javax.persistence-api -->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Some way i fixed using the #Transient tag and my entities were correctly persisted, but when i tried to query them i got a null in the OneToMany relation bcz it tells hibernate not to do something with that attribute...
emf = Persistence.createEntityManagerFactory("Persistencia");
manager = emf.createEntityManager();
This is where the exception shows
#UPDATE
Somehow i figured out that #OneToMany only accepts Collection Type as List,set, Map, etc but not "ArrayList" and i just changed the data type and it work fine..
#Transient - tells hibernate not persist such fields, that's why you have null at this fields. Also that's why you don't get problem again.
#ManyToOne are Lazy by default, so you should get them inside transaction.
You can achive this to annotate method where you use this property with #Transactional if you use JPA. Or you can use methods beginTransaction(), endTransaction() from EntityManager.
As long as your entity will go from transactional scope error will occure again. So convert your entity to dto before gone from transactional scope.
Another solution you can annotate your fields as Eager, so they will be downloaded from database with parent entity.
But Eager - bad solution, don't use it if don't know what is it.
I will try to answer the question but certain things depends on your setup i.e using as Java SE or J2EE application.
For Java SE, make sure you have your persistence file inside META-INF/persistence.xml under resources folder, Please check this article or in docs
For J2EE application, you generally configure the JNDI name in your server's configuration and then use that JNDI name inside your persistence.xml.
Also, please check all your database credentials and check access to it manually and follow the stack trace, it will tell you complete story what is going wrong.

Eclipselink: error writing objects to/retrieving objects from persistence database

I recently switched development machines and now writing objects to/retrieving objects from the persistence database is not working any longer. This happens when I try to debug the webapp project on my new machine.
It works on my old laptop but somehow won't on the new one. I also deployed the webapp to an server and there everything works as expected.
I get the following two error message while interacting with the database:
Writing objects to the database:
SEVERE: Exception sending context initialized event to listener instance of class org.example.webapp.startup.ServletContextClass
java.lang.IllegalArgumentException: Object: org.example.utility.trs.objects.ChangeLog#789a464b is not a known entity type.
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerNewObjectForPersist(UnitOfWorkImpl.java:4222)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.persist(EntityManagerImpl.java:496)
at org.example.webapp.changelog.dao.ChangeLogDao.addChangeLog(ChangeLogDao.java:42)
at org.example.webapp.startup.ServletContextClass.initializeChangeLog(ServletContextClass.java:104)
at org.example.webapp.startup.ServletContextClass.contextInitialized(ServletContextClass.java:59)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4797)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5221)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Code to write to the database:
public void addChangeLog(ChangeLog changeLog, EntityManagerFactory emf) {
String changeLogId = changeLog.getModelResource();
if(!contentProvider.containsKey(changeLogId)) {
//create new user
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(changeLog);
em.getTransaction().commit();
em.close();
contentProvider.put(changeLogId, changeLog);
}
Retrieving objects from the database:
SEVERE: Exception sending context initialized event to listener instance of class org.example.webapp.startup.ServletContextClass
java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
Exception Description: Problem compiling [SELECT c FROM ChangeLog c].
[14, 23] The abstract schema type 'ChangeLog' is unknown.
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1585)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1605)
at org.example.webapp.startup.ServletContextClass.contextInitialized(ServletContextClass.java:59)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4797)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5221)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Code to read from the database:
List<ChangeLog> changeLogList = em.createQuery("SELECT c FROM ChangeLog c",
ChangeLog.class).getResultList();
Here is how the ChangeLog class looks like:
package org.example.utility.trs.objects;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
#Entity
#NamedQuery(name="ChangeLog.findAll", query="SELECT c FROM ChangeLog c")
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class ChangeLog implements Serializable {
private static final long serialVersionUID = 123L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long changeLogId;
...
}
This is the persistence.xml file:
<?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="webapp-name" transaction-type="RESOURCE_LOCAL">
<class>org.example.utility.trs.objects.ChangeLog</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<!-- mysql persistence driver -->
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/persistence"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.username" value="admin"/>
<property name="javax.persistence.jdbc.password" value="password"/>
<!-- EclipseLink should create the database schema automatically -->
<property name="eclipselink.ddl-generation.output-mode" value="database" />
<property name="javax.persistence.jdbc.user" value="admin"/>
</properties>
</persistence-unit>
</persistence>
Here is the part of the pom.xml file that includes the persistence libraries. I can post the whole file if this of any assistence:
<!-- persistence api -->
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.5.0</version>
</dependency>
I can connect to the database and there is a table with content that I was able to create and read on my old development machine.
Thus I assume that the issue is rather with the configuration of eclipselink than an actual problem in the code. Maybe it is an issue with the configuration of the JPA facet in the eclipse project.
However I have no idea how to debug this issue.
On the other hand the ChangeLog class is in a from a different project that is stored in my local Maven repository and is not defined in the webapp project. So this might be an issue. This was never a problem on my old machine though.
Any help is appreciated
So after some testing I finally figured out what went wrong. I leave this here if anyone else comes across this problem.
It turned out that while deploying the code to the new development machine I changed some of the dependency versions in my pom.xml file. So I created the database table with version 2.6.4 of the eclipselink API.
On the new development machine I changed it to version 2.5 and recompiled the project which broke the extraction of the objects from the database.
Once I changed the version back it worked again.

No persistence provider for EntityManager for Hibernate in Maven

I am getting this error:
Exception in thread "main" javax.persistence.PersistenceException: No Persistence provider for EntityManager named tarefas at
javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:61)
My jars is okay, as you seem in the pom.xml
My main class:
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class GeraTabelas {
public static void main(String[] args)
{
EntityManagerFactory factory = Persistence.createEntityManagerFactory("tarefas");
factory.close();
}
}
pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.2.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.9.Final</version>
</dependency>
persistence.xml
<persistence-unit name="tarefas">
<!-- provedor/implementacao do JPA -->
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<!-- entidade mapeada -->
<class>br.com.abc.models.Usuario</class>
<properties>
<property name="hibernate.connection.url" value= .... //The rest of properties...
</properties>
</persistence-unit>
It may be the position of the pom.xml file in the wrong location? I did this way because of others posts that said it was this way but this interrogation point appears in the folders and I am beginner in Maven to know what it is.
Thanks.

JPA 2.1 Schema gereration problems

I'm trying to use pure JPA 2.1 as a standardized way to generate db schema.
(Underlying database - Derby embedded, persistence provider - eclipseLink)
To check generated scripts I set <property name="javax.persistence.schema-generation-target" value="database-and-scripts"/>
And as a result I got it with some 'sequence' table within.
And although ... ERROR 42X05: Table/View 'SEQUENCE' does not exist.
Can somebody help to understand such a weird behavior?
maven dependencies:
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.9.1.0</version>
</dependency>
Entity:
import javax.persistence.*;
#Entity
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
// getters/setters/constructors
}
main body:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("chapter04PU");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
em.persist(new Book("Neuromancer"));
tx.commit();
em.close();
emf.close();
persistence-unit:
<persistence-unit name="chapter04PU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>Book</class>
<properties>
<!--<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>-->
<property name="javax.persistence.schema-generation-action" value="drop-and-create"/>
<property name="javax.persistence.schema-generation-target" value="database-and-scripts"/>
<property name="javax.persistence.schema-generation.scripts.action" value="drop-and-create"/>
<property name="javax.persistence.schema-generation.scripts.create-target" value="create.sql"/>
<property name="javax.persistence.schema-generation.scripts.drop-target" value="delete.sql"/>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:derby:chapter04DB;create=true"/>
</properties>
generated script file:
CREATE TABLE BOOK (ID BIGINT NOT NULL, TITLE VARCHAR(255), PRIMARY KEY (ID))
CREATE TABLE SEQUENCE (SEQ_NAME VARCHAR(50) NOT NULL, SEQ_COUNT DECIMAL(15), PRIMARY KEY (SEQ_NAME))
INSERT INTO SEQUENCE(SEQ_NAME, SEQ_COUNT) values ('SEQ_GEN', 0)
Update
After replacing:
<property name="javax.persistence.schema-generation-action" value="drop-and-create"/>
with:
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
I can 'normally' run app (with exit code 0).
But I still take this weird message while first run (with absent DB).
the second run is clear - no such messages.
Thanks a lot for your suggestion to use <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>!
As for the second problem, the main culprit here is #GeneratedValue(strategy=GenerationType.AUTO) which probably was a default value provided by IDE on entity creation. Given the way org.eclipse.persistence.jpa.PersistenceProvider processes this annotation (leading to the exception about non-existant 'SEQUENCE' table), the simplest solution would be to just use #GeneratedValue(strategy=GenerationType.IDENTITY) instead.

JPA exception: Object: ... is not a known entity type

I'm new to JPA and I'm having problems with the autogeneration of primary key values.
I have the following entity:
package jpatest.entities;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class MyEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
private String someProperty;
public String getSomeProperty() {
return someProperty;
}
public void setSomeProperty(String someProperty) {
this.someProperty = someProperty;
}
public MyEntity() {
}
public MyEntity(String someProperty) {
this.someProperty = someProperty;
}
#Override
public String toString() {
return "jpatest.entities.MyEntity[id=" + id + "]";
}
}
and the following main method in other class:
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPATestPU");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
MyEntity e = new MyEntity("some value");
em.persist(e); /* (exception thrown here) */
em.getTransaction().commit();
em.close();
emf.close();
}
This is my persistence unit:
<?xml version="1.0" encoding="UTF-8"?>
<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="JPATestPU" transaction-type="RESOURCE_LOCAL">
<provider>oracle.toplink.essentials.PersistenceProvider</provider>
<class>jpatest.entities.MyEntity</class>
<properties>
<property name="toplink.jdbc.user" value="..."/>
<property name="toplink.jdbc.password" value="..."/>
<property name="toplink.jdbc.url" value="jdbc:mysql://localhost:3306/jpatest"/>
<property name="toplink.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="toplink.ddl-generation" value="create-tables"/>
</properties>
</persistence-unit>
</persistence>
When I execute the program I get the following exception in the line marked with the proper comment:
Exception in thread "main" java.lang.IllegalArgumentException: Object: jpatest.entities.MyEntity[id=null] is not a known entity type.
at oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.registerNewObjectForPersist(UnitOfWorkImpl.java:3212)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerImpl.persist(EntityManagerImpl.java:205)
at jpatest.Main.main(Main.java:...)
What am I missing?
I ran into this same problem using NetBeans IDE 6.9.
Apparently, this is a known issue.
See
http://wiki.eclipse.org/EclipseLink/Development/JPA_2.0/metamodel_api#DI_101:_20100218:_Descriptor.javaClass_is_null_on_a_container_EM_for_a_specific_case.
Also see http://netbeans.org/bugzilla/show_bug.cgi?id=181068.
I added the last line below to persistence.xml and it fixed it for me.
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<!-- Add the following to work around exception issue -->
<exclude-unlisted-classes>false</exclude-unlisted-classes>
As Charles pointed out in his answer, the problem is not the id generation, but the persistence layer not finding the entity.
As you, I am also new to JPA. I have tried to write a "Hello World" JPA application using org.eclipse.persistence.jpa.PersistenceProvider when I got this error. The mentioned workaround also worked for me. Moreover, through trial-error I also found that to declare your entities, you must always anotate #entity in each entity and:
if you set exclude-unlisted-classes to true, you also have to list the entities within class elements in your persistence.xml
if you set exclude-unlisted-classes to false the persistence layer can find the entities regardles of the class element in your persistence.xml.
TopLink used to require you to explicitly set GenerationType.IDENTITY for MySQL, so change this and drop the database. Then try running your sample again. Further you might also want to explcitly set the database platform:
<property name="toplink.platform.class.name"
value="oracle.toplink.platform.database.MySQL4Platform"/>
Also I vaguely remember that you have to run Toplink using its Java agent in order to make it function properly with a resource local entitymanager.
I did however successfully run your example using EclipseLink (which you should use since Toplink is outdated). Only cavat was that I did not have MySQL server handy, so I ran it using H2. I used the following Maven pom.xml to resolve the dependencies:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.randompage</groupId>
<artifactId>sandbox</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>sandbox</name>
<repositories>
<repository>
<id>EclipseLink Repo</id>
<url>http://www.eclipse.org/downloads/download.php?r=1&nf=1&file=/rt/eclipselink/maven.repo</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.0.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.2.130</version>
</dependency>
</dependencies>
</project>
and this 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="JPATestPU" transaction-type="RESOURCE_LOCAL">
<provider>
org.eclipse.persistence.jpa.PersistenceProvider
</provider>
<class>org.randompage.MyEntity</class>
<properties>
<property name="javax.persistence.jdbc.user" value="johndoe"/>
<property name="javax.persistence.jdbc.password" value="secret"/>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:h2:~/.h2/testdb;FILE_LOCK=NO"/>
<property name="eclipselink.ddl-generation" value="create-tables"/>
<property name="eclipselink.logging.level" value="INFO"/>
</properties>
</persistence-unit>
</persistence>
With these settings your code ran as expected.
I use this syntax rather than type AUTO
#javax.persistence.Id
#javax.persistence.GeneratedValue(strategy = GenerationType.IDENTITY)
Then, I use the simple type "long" for ID's with a lowercase l :
private long taskID;
This may be unrelated, but I also specify a different table name for my entities:
#javax.persistence.Entity(name = "Tasks")
public class Task implements Serializable
I ran into the same exception, when deploying web applications to GlassFish v3 (which uses EclipseLink as its JPA provider). I am not sure it's the same scenario as above - but the explanation for this bug in my case might help others :-) - turns out there's a bug in EclipseLink, when running under OSGi (which is the case in GlassFish), which leads EclipseLink to hold on to an "old" version of the entity class when re-deploying, resulting in this exception. The bug report is here.
As far as I know, whenever I get this error, I just re-start glassfish. Works everytime.
if you are only getting this error in junit
try adding this in persistence.xml
<jar-file>file:../classes</jar-file>
You could try and leave the definition out of the persistnce.xml The Persistence provider should than scan all classes in the classpath for #Entity annotations.
I also have to add one other item to my persistence.xml when changing class/table defs so that the EM knows to build/update tables:
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(SchemaAction=&apos;refresh&apos;)"/>
If I want a fresh start, I instead use:
<!--<property name="openjpa.jdbc.SynchronizeMappings"
value="buildSchema(SchemaAction='dropDB,add')"/>
-->
I noticed that in your persistence.xml schema management is only set to "create tables" as opposed to drop/create, or update
Check the class output folder of eclipse, sometimes you change the xml and it was not updated.
The combination of deployment from within NetBeans 8.2 on Glassfish 4.1 on a Maven project with the "Debug" function of a project can cause an outdated version to be re-deployed (unclear where the fault lies).
Stop GlassFish, delete [glassfish base]/glassfish/domains/[domain name]/generated/, restart and redeploy.

Categories

Resources