3
votes

I am getting the following exception and have done all this 1000 times before but now I am getting errors:

ValidationException Exception Description: [class com.smartphonedev.rsvplaw.entities.Staff] uses a non-entity [class com.smartphonedev.rsvplaw.entities.Address] as target entity in the relationship attribute [field addresses]..

here are the entities in question. Can someone help me identify what is wrong with my relationships?

<code>
@Entity
@Table(name="address")
public class Address implements Serializable,
{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

@Column(name="addressType")
@Enumerated(EnumType.ORDINAL)
private AddressType addressType;

@Column(name="streetLineOne")
private String streetLineOne;

@Column(name="streetLineTwo")
private String streetLineTwo;

@Column(name="city")
private String city;

@Column(name="adState")
private String state;

@Column(name="postCode")
private String postCode;    

@OneToMany(fetch=FetchType.LAZY, targetEntity=PhoneNumber.class, cascade = {CascadeType.MERGE,   CascadeType.REFRESH, CascadeType.DETACH},orphanRemoval=true)
@JoinColumn(name="phoneNumbers")
private Collection<PhoneNumber> phoneNumbers;
…..
}

@Entity
@Table(name="staff")
public class Staff implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

//private Profile profile;
@OneToOne(fetch=FetchType.LAZY,cascade = {CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
@JoinColumn(name="permission")
private Permission permission;

@OneToOne(fetch=FetchType.LAZY,cascade = {CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
@JoinColumn(name="login")    
private Login login;

@Column(name="firstName")
private String firstName;

@Column(name="surnameName")
private String surnameName;

@Column(name="emailAddress")
private String emailAddress;

@OneToMany(fetch=FetchType.LAZY, targetEntity=PhoneNumber.class, cascade = {CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH},orphanRemoval=true)
@JoinColumn(name="phoneNumbers")
private Collection<PhoneNumber> phoneNumbers;

@OneToMany(fetch=FetchType.LAZY, targetEntity=Address.class, cascade = {CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH},orphanRemoval=true)
@JoinColumn(name="addresses")
private Collection<Address> addresses;
}
</code

Adding the phoneNumber class @Entity @Table(name="phone") public class PhoneNumber implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id;

@Column(name="numberType")
@Enumerated(EnumType.ORDINAL)
private PhoneNumberType numberType;

@Column(name="phoneNumber")
private String phoneNumber;
}
</code>

Adding persistance.xml

<code>

<?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="RSVPLawServerPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/RSVPLaw</jta-data-source>
<class>com.smartphonedev.rsvplaw.entities.PhoneNumber</class>
<class>com.smartphonedev.rsvplaw.entities.Address</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<shared-cache-mode>NONE</shared-cache-mode>
<validation-mode>CALLBACK</validation-mode>
<properties>
  <property name="eclipselink.target-server" value="SunAS9"/>  
  <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
  <property name="eclipselink.ddl-generation" value="create-tables"/>
  <property name="eclipselink.ddl-generation.output-mode" value="database"/>
  <property name="javax.persistence.schema-generation.database.action" value="create"/>
</properties>
</persistence-unit>
</persistence>

<code> 
1
@OneToMany should be mappedBy, while @ManyToOne should be followed by @JoinColumnguido
@guido OneToMany has "mappedBy" ONLY IF it is bidirectional ... so how do you know it is in this case when he doesnt show the PhoneNumber class?Neil Stockton
Please note they are all unidirectionalDamien Cooke
Is your class Address listed in the persistence.xml ? Looks like it's not "known" to be an entity.geert3

1 Answers

3
votes

I am in this same situation while separating a @ManyToMany relationship into two @OneToMany/@ManyToOne relationships, and I solved it. Here's some tips, concluded from all answers above, and my discovery:

  1. make sure the class is with annotation @Entity, and has correct Table(name=xxx).
  2. If using JPA, make sure it's in persistence.xml. If using Hibernate, make sure it's in hibernate.cfg.xml. If using both, in both files.
  3. Make sure the classes is in the same JAR as the mapping/cfg files.
  4. One thing I found: You don't have to remove mappedBy=, but you have to ensure, that the attribute name is unique in your whole project!

Like in my case: if I remove mappedBy in my @OneToMany side(while @ManyToOne side is a intermediate class for a @ManyToMany relationship, which has its own fields, so I have to make it @Entity instead of using middle table directly), EclipseLink complains for a table named "EntityA_MiddleEntity", which doesn't exist. I guess, when encountering mappedBy=xxx, EclipseLink looks for all entities with fields named xxx, and when it exists in more than one class, and one of these classes is the intermediate class for @ManyToMany, it fails to relate them. So I changed the attribute name in the middle class and all works fine.