JPA Relation between classes, referring to their Interfaces - java

I have two classes with their respective interfaces between which I want to create a JPA #OneToOne Relation. This fails with [class EmployeeImpl] uses a non-entity [class Adress] as target entity in the relationship attribute [field adress].
First Interface / Class:
public interface Employee {
public long getId();
public Adress getAdress();
public void setAdress(Adress adress);
}
#Entity(name = "EmployeeImpl")
#Table(name = "EmployeeImpl")
public class EmployeeImpl implements Employee {
#Id
#Column(name = "employeeId")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#OneToOne(cascade = CascadeType.PERSIST)
private Adress adress;
// snip, getters and setters
}
Second Interface / Class:
public interface Adress {
public long getId();
public String getStreet();
public void setStreet(String street);
}
#Entity(name = "AdressImpl")
#Table(name = "AdressImpl")
public class AdressImpl implements Adress {
#Id
#Column(name = "AdressId")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "Street")
private String street;
// Snip getters and setters
}
The persistence.xml looks like this:
<?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="employee"
transaction-type="RESOURCE_LOCAL">
<class>EmployeeImpl</class>
<class>AdressImpl</class>
<properties>
<property name="eclipselink.create-ddl-jdbc-file-name"
value="create-matterhorn-employee.jdbc" />
<property name="eclipselink.drop-ddl-jdbc-file-name"
value="drop-matterhorn-employee.jdbc" />
</properties>
</persistence-unit>
</persistence>
I shortened out package names and imports and such. Exception occurs when trying to create the EntityManagerFactory (where you hand over the persistence unit). I am using eclipse link 2.0.2.

Actually JPA does allow such interface relationships, but in this case you have to provide an entity class implementing the interface, in you case this will look as follows:
#OneToOne(targetEntity = AddressImpl.class)
private Adress adress;

JPA standard does not allow for interface fields (or Collection of interface fields) being entity relationships. Some JPA implementations do support it (e.g DataNucleus JPA), but its a vendor extension to the spec. Consequently you either use one of those implementations or change your model (or add extra annotations/XML to define what type is actually stored there).

Related

JPA Repository Join - Continuous Loop of data when retrieving data from DB

I have two repositories - User and Address.
User has a one to one relationship with Address and they are linked by ID. See below code snippets. When I pull data using a JPA repository, I get basically a constant loop of data.
EG:
<Data>
<User>
<id>1</id>
<name>Mary</name>
<dob>21/01/1990</dob>
<Address>
<id>1<id>
<address>123 Main Street</address>
<User>
<id>1</id>
<name>Mary</name>
<dob>21/01/1990</dob>
<Address>
<id>1<id>
<address>123 Main Street</address>
<User>
....
and so on like this causing my query to take a large amount of time to run. Is there anyway to stop the User object from being returned within the Address object? Any help would be greatly appreciated.
#Entity
#Data
#Table(name = "ADDRESS")
public class Address{
#Id
#Column()
private String id;
#Column()
private String address;
#OneToOne (fetch = FetchType.LAZY)
#JoinColumn(name = "id")
private User user;
}
#Entity
#Data
#Table(name = "User")
public class User{
#Id
#Column()
private String id;
#Column()
private String name;
#Column()
private String dob;
#OneToOne ()
#JoinColumn(name = "id")
private Address address;
}
This is normal behaviour. Serializers call getters to serialize data which are intercepted by the Hibernate Proxy loading the data even if they are lazy. To prevent this, You have to add #JsonBackReference to the address field in your User class, and #JsonManagedReference to the user field in your Address class.

JPA java.lang.ClassFormatError issue

I have an issue with starting the JPA and Derby project. I have the following error:
Exception in thread "main" java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/persistence/Persistence
My Main.java is:
public class Main {
private static final String PERSISTENCE_UNIT_NAME = "customers";
private static EntityManagerFactory factory;
public static void main(String[] args) {
factory = Persistence.createEntityManagerFactory("todos");
EntityManager em = factory.createEntityManager();
Query q = em.createQuery("select t from CUSTOMER t");
List<Customer> customerList = q.getResultList();
for (Customer customer : customerList) {
System.out.println(customer);
}
System.out.println("Size: " + customerList.size());
em.getTransaction().begin();
Customer customer = new Customer();
customer.setCity("Warsaw");
customer.setCountry("USA");
customer.setName("John");
customer.setStreet("Street");
em.persist(customer);
em.getTransaction().commit();
em.close();
}
}
My persistence.xml:
<?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="todos" transaction-type="RESOURCE_LOCAL">
<class>b.model.Product</class>
<class>b.model.Book</class>
<class>b.model.Movie</class>
<class>b.model.Customer</class>
<class>b.model.Order</class>
<class>b.model.OrderElement</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="javax.persistence.jdbc.url"
value="jdbc:derby://localhost:1527/baza;create=true" />
</properties>
</persistence-unit>
</persistence>
I have 2 dependencies in my project:
derbyclient-10.12.1.1.jar
javaee-api-6.0.jar
Any ideas on what am I doing wrong?
I have all the Model classes (like Customer) defined like this:
#Data
#Entity(name = "CUSTOMER")
public class Customer {
#Id
#Column(name = "CUSTOMER_ID", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private long customerId;
#Column(name = "NAME")
private String name;
#Column(name = "SURNAME")
private String surname;
#Column(name = "STREET")
private String street;
#Column(name = "CITY")
private String city;
#Column(name = "ZIP_CODE")
private String zipCode;
#Column(name = "COUNTRY")
private String country;
#OneToMany(mappedBy="customer",targetEntity=Order.class, fetch= FetchType.EAGER)
private Collection orders;
}
This is caused most probably by packaging the javaee-api jar inside your WAR. It contains only the method signatures, but no method bodies, thus one cannot run/test/deploy an application using it. Its sole purpose is to compile your app against it, thus making sure you follow the javaee api specs and avoid dependencies to a concrete implementation. Also one must not package any APIs provided by the server within the WAR.

Hibernate Annotation on parent fields

I have a class that is a POJO with no special Hibernate annotations or information, like so:
public class Parent{
Long id;
String foo;
String bar;
/* ... getters and setters, toString(), etc... */
}
I would like to create a child class that has the Hibernate annotations on it. The idea is that the first class will not have any dependencies on it, and the second will have all of the JPA/Hibernate specific stuff. How can I do that without re-creating all the fields in the parent? I would like to put Hibernate annotations on the class
#Entity
public class PersistentChild extends Parent{
// ????
}
You can use the #MappedSuperclass annotation on the POJO, then add the other annotations, as it were a normal JPA entity. But in this case, the annotations will only affect the entity classes, which are inheriting from it. Example:
#MappedSuperclass
public class Parent implements Serializable {
#Id
Long id;
#Column(name = "foo", required = true)
String foo;
#Column(name = "bar", required = false)
String bar;
/* ... getters and setters, toString(), etc... */
}
If you really do not want to modify the superclass, you can use a mapping file:
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">
<mapped-superclass class="Parent">
<!-- add your mapping here -->
</mapped-superclass>
</entity-mappings>
Alternative approach
Also, you can just add the #MappedSuperclass annotation, then define all properties like this:
#Entity
#AttributeOverrides({
#AttributeOverride(name = "foo", column=#Column(name = "foo", required = true)),
#AttributeOverride(name = "bar", column=#Column(name = "bar", required = false))
})
public class PersistentChild extends Parent {
#Id #GeneratedValue
Long id;
}
If you want to externalize the mapping you have to use xml-mapping file.

#OneToOne or #ManyToOne references an unknown entity

I am trying to make a relationship between 2 entities in different jar.
This is a first entity which is in main project:
#Entity(name = "StdyDtlLabelBean")
#Table(name = "STDY_DTL_LABEL")
public class StdyDtlLabelBean implements Serializable {
#EmbeddedId
private StdyDtlLabelBeanPk id;
#ManyToOne(targetEntity = StdyDtlSubject.class)
#JoinColumns({
#JoinColumn(name="STUDY_ID", insertable = false, updatable = false, referencedColumnName="STUDY_ID"),
#JoinColumn(name="SUBJECT_ID", insertable = false, updatable = false, referencedColumnName="SUBJECT_ID")
})
private StdyDtlSubject subject;
//getters and setters
}
This one is an entity which is in library project as a jar file:
#Entity
#Table(name = "STDY_DTL_SUBJECT")
public class StdyDtlSubject implements Serializable {
private static final long serialVersionUID = 2479124604L;
public StdyDtlSubject() {
}
#EmbeddedId
private StdyDtlSubjectPK key;
//getters and setters
}
#Embeddable
public class StdyDtlSubjectPK implements Serializable {
private static final long serialVersionUID = 6691432687933341920L;
#Column(name = "STUDY_ID")
private Integer studyId;
#Column(name = "SUBJECT_ID")
private String subjectId;
public StdyDtlSubjectPK() {
}
Here is the persistence unit:
<persistence-unit name="stdyPersistence" transaction-type="RESOURCE_LOCAL">
<jta-data-source>java:comp/env/jdbc/OraclePooledDS</jta-data-source>
<class>com.ctasc.ctpm.jpa.StdyDtlSubject</class>
<class>stdy.brms.beans.StdyDtlLabelBean</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
</properties>
</persistence-unit>
When I create an entity manager factory I gets following error:
#OneToOne or #ManyToOne on stdy.brms.beans.StdyDtlLabelBean.subject references an unknown entity: com.ctasc.ctpm.jpa.StdyDtlSubject
But if I remove a relationship annotation from StdyDtlLabelBean entity and create named queries on StdyDtlSubject entity. Those named queries work fine. Also, if I copy StdyDtlSubject class to my main project, it works fine. I gets this error only if I put relationship between them.
I've tried adding
<jar-file>ctpm.jar</jar-file>
<jar-file>lib/ctpm.jar</jar-file>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<property name="hibernate.archive.autodetection" value="class, hbm" />
<property name="packagesToScan" value="com.ctasc.ctpm.jpa" />
None of them helped me to solve this. Could you please suggest something to solve this problem?
Ensure that the jar which you want to relate to has a persisence.xml in it's META-INF with all entities in the jar enlisted.

org.hibernate.AnnotationException: #OneToOne or #ManyToOne on entities.Ques#tion.examId references an unknown entity: long

I'm trying to setup JPA with a hibernate implementation for the first time with this test project. Ran into the following error:
Exception in thread "main" javax.persistence.PersistenceException: [PersistenceUnit: ExamModulePu] Unable to build EntityManagerFactory
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:924)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:899)
at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:59)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:63)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:47)
at service.tests.ExamServiceTest.main(ExamServiceTest.java:18)
Caused by: org.hibernate.AnnotationException: #OneToOne or #ManyToOne on entities.Question.examId references an unknown entity: long
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:109)
at org.hibernate.cfg.Configuration.processEndOfQueue(Configuration.java:1536)
at org.hibernate.cfg.Configuration.processFkSecondPassInOrder(Configuration.java:1457)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1365)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1756)
at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:96)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:914)
These are my entities:
#Entity
public class Exam implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
private int numQuestions;
private int minutesAllotted;
private Date startDate;
private Date endDate;
#OneToMany(mappedBy = "examId", orphanRemoval = true)
private List<Question> questionList;
// Getters and setters here..
}
#Entity
public class Question implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#ManyToOne
private long examId;
private int points;
private int timeLimit;
private String text;
private String category;
#Embedded
private List<Answer> answerList;
}
#Embeddable
public class Answer implements Serializable {
private int optionNumber;
private String text;
private boolean correct;
}
This is what my persistence.xml looks like:
<?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="ExamModulePu"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>entities.Exam</class>
<class>entities.Question</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/exammoduledb" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="root" />
<property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
</persistence-unit>
</persistence>
I haven't created any of the tables, but instead am depending on the hibernate.hb2mddl.auto to do so. But I believe my error springs up even before that happens as it can't generate the persistence unit. Any ideas what I'm doing wrong? I'm making sure I import only javax.persistence.*;
If you look closely at your stacktrace, you will see
Caused by: org.hibernate.AnnotationException: #OneToOne or #ManyToOne on entities.Question.examId references an unknown entity: long
So this field
#ManyToOne
private long examId;
is causing the problem. #ManyToOne has a paramater targetEntity which says:
(Optional) The entity class that is the target of the association.
Defaults to the type of the field or property that stores the association.
Since you haven't provided that parameter, it defaults to long, which is not a managed Entity.
You'll probably want to use
#ManyToOne(targetEntity = Exam.class)
private long examId;
otherwise it won't know what to map to. Or even better
#ManyToOne
private Exam exam;
Just add the class Team to the "hibernate-cfg.xml" file, because Hibernate doesn't identify without adding into it.
FYI, this sometimes happens if you have a hibernate annotation:
#org.hibernate.annotations.Entity
and a JPA annotation:
#javax.persistence.Entity
mixed up
Edit:
Explicitly import the javax annotation.
It took me hours to find the actual issue
I had forgotten the #Entity annotation on the Parent class and the error use to show on the child class.
In my case Hibernate was not able to identify the entity because I had not added that entity in sessionfactory using .addAnnotatedClass(XYZ.class) so it was not able to find that particular entity.

Categories

Resources