I have a class called jobprofile, which contains the following OneToMany Relation:
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "profile")
private List<JobLanguageProficiency> jobLanguageProficiency;
The referenced class "JobLanguageProficiency" looks like this:
package ch.alv.jobmatch.entity.aux;
import ch.alv.jobmatch.entity.job.Jobprofile;
import javax.persistence.*;
#Entity
#Table(name = "job_language_proficiency")
public class JobLanguageProficiency {
#Id
private int id;
#ManyToOne
#JoinColumn(name = "jobprofile_jobprofile_id")
private Jobprofile profile;
#OneToOne
private Languages languages;
#OneToOne
private LangProficiency langProficiency;
public Languages getLanguages() {
return languages;
}
public void setLanguages(Languages languages) {
this.languages = languages;
}
public LangProficiency getLangProficiency() {
return langProficiency;
}
public void setLangProficiency(LangProficiency langProficiency) {
this.langProficiency = langProficiency;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Jobprofile getProfile() {
return profile;
}
public void setProfile(Jobprofile profile) {
this.profile = profile;
}
}
Basically, it just contains two references to a language, and a proficiency for it.
When I try to create/persist a jobprofile, it fails as soon as it tries to insert the language data in the database.
This is the error:
Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException:
Could not write content: (was java.lang.NullPointerException) (through
reference chain:
org.springframework.data.rest.webmvc.json.["content"]); nested
exception is com.fasterxml.jackson.databind.JsonMappingException: (was
java.lang.NullPointerException) (through reference chain:
org.springframework.data.rest.webmvc.json.["content"])
I suspect the source of the error lies in the JSON, since the OneToMany Relation works perfectly when I insert the data manually.
The relevant part of the JSON looks like this:
job_language_proficiency: Array[1]
0: Object
languages: "http://localhost:9000/api/languages/de"
proficiency_code: "http://localhost:9000/api/langproficiency/C1"
Any ideas why this doesn't work?
EDIT: Updated the JSON so it contains objects instead of links.
LangProficiency entity:
package ch.alv.jobmatch.entity.aux;
import javax.persistence.*;
#Entity
#Table(name = "LangProficiency")
public class LangProficiency {
#Id
#Column(name = "proficiency_code")
private String proficiency_code;
private String description_de;
private String description_fr;
private String description_it;
private String description_en;
public String getProficiency_code() {
return proficiency_code;
}
public void setProficiency_code(String proficiency_code) {
this.proficiency_code = proficiency_code;
}
public String getDescription_de() {
return description_de;
}
public void setDescription_de(String description_de) {
this.description_de = description_de;
}
public String getDescription_fr() {
return description_fr;
}
public void setDescription_fr(String description_fr) {
this.description_fr = description_fr;
}
public String getDescription_it() {
return description_it;
}
public void setDescription_it(String description_it) {
this.description_it = description_it;
}
public String getDescription_en() { return description_en; }
public void setDescription_en(String description_en) { this.description_en = description_en; }
}
Languages entity:
package ch.alv.jobmatch.entity.aux;
import javax.persistence.*;
import java.io.Serializable;
#Entity
#Table(name = "Languages")
public class Languages implements Serializable {
#Id
#Column(name = "languages")
private String languages;
private String description_de;
private String description_fr;
private String description_it;
private String description_en;
public String getLanguages() {
return languages;
}
public void setLanguages(String languages) {
this.languages = languages;
}
public String getDescription_de() {
return description_de;
}
public void setDescription_de(String description_de) {
this.description_de = description_de;
}
public String getDescription_fr() {
return description_fr;
}
public void setDescription_fr(String description_fr) {
this.description_fr = description_fr;
}
public String getDescription_it() {
return description_it;
}
public void setDescription_it(String description_it) {
this.description_it = description_it;
}
public String getDescription_en() { return description_en; }
public void setDescription_en(String description_en) { this.description_en = description_en; }
}
Your JSON structure should match your Java Mapping, otherwise your object won't be persisted by your ORM, that's why you are getting such Mapping error.
In your case in your Entity you have a relationship with two entities that should be objects in your JSON:
#OneToOne
private Languages languages;
#OneToOne
private LangProficiency langProficiency;
But in your JSON, you have set those two objects as simple strings:
languages: "http://localhost:9000/api/languages/de"
proficiency_code: "http://localhost:9000/api/langproficiency/C1"
They should be matching Languages and langProficiency objects, and proficiency_code should be named langProficiency respectively like your Java attribute.
Related
I am trying to perform a fetch using Criteria API with restrictions on the variable of an embedded entity. But I am getting the below error,
org.hibernate.QueryException: could not resolve property: cpm of: org.sorabh.SystemEnt
Below is my SystemEnt entity,
#Entity
#Table(name="system")
public class SystemEnt implements Serializable{
#Id
#Column(name="pmTpId", nullable = false)
private int id;
#Column(name="pmMeasureId", nullable = false)
private int pmMeasureId;
#OneToOne(fetch=FetchType.EAGER)
#JoinColumn(name="pmMeasureId", insertable=false, updatable=false)
private Cpm cpm;
private String mapper;
public int getId() {
return id;
}
public int getPmMeasureId() {
return pmMeasureId;
}
public Cpm getCpm() {
return cpm;
}
public String getMapper() {
return mapper;
}
public void setId(int id) {
this.id=id;
}
public void setPmMeasureId(int pmMeasureId) {
this.pmMeasureId=pmMeasureId;
}
public void setCpm(Cpm cpm) {
this.cpm=cpm;
}
public void setMapper(int mapper) {
this.mapper=mapper;
}
My CpmMeas contains
#Entity
#Table(name="cpm")
public class Cpm implements Serializable{
#Id
#Column(name="pmMeasureId", nullable = false)
private int pmMeasureId;
#Column(nullable=false)
private int pmGranularity
//getters and setters
public void setPmMeasureId(int pmMeasureId) {
this.pmMeasureId=pmMeasureId;
}
public int getPmMeasureId() {
return pmMeasureId;
}
public void setPmGranularity(int pmGranularity) {
this.pmGranularity=pmGranularity;
}
public int getPmGranularity() {
return pmGranularity;
}
I do the below in my serviceImpl:
Criteria cr = session.createCriteria(SystemEnt.class);
cr.add(Restrictions.like("mapper", "Test", MatchMode.START));
cr.add(Restrictions.eq("cpm.pmGranularity", 1));
I have tried using aliases as suggested in a few other posts on SO, but it doesn't seem to solve the issue.
Also, it is not having issues in resolving mapper, i.e only the nested entities and corresponding variables are not getting resolved.
Use alias , as
Criteria cr = session.createCriteria(SystemEnt.class);
cr.createAlias("cpm","cpm");
cr.add(Restrictions.like("mapper", "Test", MatchMode.START));
cr.add(Restrictions.eq("cpm.pmGranularity", 1));
anyway the field mapper should be a String, in your sample code it is defined as an int.
I tested and without a doubt it works fine.
I'm developing an application using java with hibernate 4.2.6 and spring 4.0.1. My application is a REST FULL application. for this I use jackson. My entities are as follow:
Calk.java:
#Entity
public class Calk {
#Id
#GeneratedValue
private Long id;
#OneToMany(mappedBy="calk", fetch=FetchType.LAZY)
List<BaseLayer> baseLayer = new ArrayList<BaseLayer>();
public void addBaseLayer(BaseLayer baseLayer){
this.baseLayer.add(baseLayer);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#JsonIgnore
public List<BaseLayer> getBaseLayer() {
return baseLayer;
}
public void setBaseLayer(List<BaseLayer> baseLayer) {
this.baseLayer = baseLayer;
}
}
BaseLayer.java:
#Entity
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="layer")
#JsonSubTypes(
{
#JsonSubTypes.Type(value=PointLayer.class, name="point")
})
#DiscriminatorValue("BaseLayerDiscriminator")
public class BaseLayer {
#Id
#GeneratedValue
protected Long gid;
#ManyToOne(fetch = FetchType.LAZY)
protected Calk calk;
public Long getGid(){
return gid;
}
public void setGid(Long gid){
this.gid = gid;
}
#JsonIgnore
public Calk getCalk(){
return calk;
}
public void setCalk(Calk calk){
this.calk = calk;
}
}
Now I have a class that extends from BaseLayer.java as follow:
PointLayer.java:
#Entity
#DiscriminatorValue("PointDiscriminator")
public class PointLayer extends BaseLayer{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Now I create a json as follow and then send it to a controller:
{"layer": "point", "calk":{"id":1}, "name": "itsme"}
Now the controller defines as follow:
#RequestMapping("\test")
public String test(#RequestBody BaseLayer baseLayer){
System.out.println(baseLayer.getName());// this print "itsme"
Calk calk = baseLayer.getCalk();//it return null
if(calk == null)
return "its null";
else
return "its not null";
}
when we call the controller it return its not null. The calk should not be null.
Where is the problem?
Update:
When I remove #JsonIgnore at getCalk, It work fine. But Why? I want to ignore getCalk but NOT ignore setCalk.
#JsonIgnore in follow:
#JsonIgnore
public List<BaseLayer> getBaseLayer() {
return baseLayer;
}
set Ignore to following by default:
public void setBaseLayer(List<BaseLayer> baseLayer) {
this.baseLayer = baseLayer;
}
You must add #JsonProperty("baseLayer") On top of set function as follow:
#JsonProperty("baseLayer")
public void setBaseLayer(List<BaseLayer> baseLayer) {
this.baseLayer = baseLayer;
}
When trying to serialize a Category I get a stackoverflow.
Exception
Warning: StandardWrapperValve[dispatcher]: Servlet.service() for
servlet dispatcher threw exception java.lang.StackOverflowError at
java.lang.ClassLoader.defineClass1(Native Method) at
java.lang.ClassLoader.defineClass(ClassLoader.java:760) at
org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.findClass(BundleWiringImpl.java:2279)
at
org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1501)
at
org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:75)
at
org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1955)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:660)
at
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152)
at
com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:100)
at
com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:21)
at
com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:183)
at
com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:541)
at
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:644)
at
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152)
Category.java
#Entity
public class Category implements DataObject, Serializable {
#Id
#GeneratedValue
private Long id;
private String title;
private String description;
#ManyToOne #JsonIgnore
private Category parent;
#Override
public long getId() {
return id;
}
#Override
public void setId(long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Category getParent() {
return null;//return parent;
}
public void setParent(Category parent) {
// this.parent = parent;
}
public boolean isMainCategory()
{
return true;// return this.parent == null;
}
/**
* Returns the chain of parent categories with the main category on index 0
* #return Chain of categories
*/
public List<Category> getParentChain()
{
List<Category> cats = new ArrayList<>();
Category current = this;
while(!current.isMainCategory())
{
cats.add(current);
current = current.getParent();
}
cats.add(current);
Collections.reverse(cats);
return cats;
}
#Override
public String toString()
{
return this.title;
}
#Override
public boolean equals(Object o)
{
if(!(o instanceof Category))return false;
Category c = (Category)o;
return c.title.equals(this.title);
}
#Override
public int hashCode()
{
return super.hashCode();
}
}
Rest Controller function
#RequestMapping(value="/{id}", method=RequestMethod.GET)
public ResponseEntity<Category> get(#PathVariable("id") long categoryId)
{
Category c = service.getCategoryRepository().ReadValue(categoryId);
if(c == null)
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
return new ResponseEntity<>(c,HttpStatus.OK);
}
Note
Even when I replace return new ResponseEntity<>(c,HttpStatus.OK); with return new ResponseEntity<>(new Category(),HttpStatus.OK); I will get a stackoverflow whilist none of the fields contain a value.
It works fine with my other classes it's only this class that causes a stackoverflow.
Sure thing, #JsonIgnore does the job. But what if we need ignored field in our JSON output?
The solution is very simple.
We annotate our 'guilty' field by #JsonManagedReference annotation on the one side of our relation (which means our #ManyToMany annotation).
And #JsonBackReference on the other side of relation (where #OneToMany has been placed).
And that's it. No more recursive loops.
Probably if you comment private Category parent; you will not have the StackOverflow. I've got the same problem in a project with circular dependencies.
The best way to solve this problem is to use the id of the parent instead of the Class like:
private Long parentId;
Edit:
The problem is with getParentChain() that is trying to be serialized. By adding #JsonIgnore before the method the problem was resolved.
One annotation solves your problem.
Add following annotation on class.
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
Other way is to annotate on Collections #JsonManagedReference for forward direction and #JsonBackReference. for backward direction in mapping.
example:
public class User{
#JsonManagedReference
#OneToMany(mappedBy = "user")
Set<Address> s = new Hashset<>();
}
public class Address{
#JsonBackReference
#ManyToOne
#JoinColumn
User user;
}
This is what i do to avoid this recursive hell.
Add #JsonIgnore to every single #OneToMany(mappedBy="xxxx") in your JPA Entities
JsonIgnore is from jackson-annotations
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.10.0</version>
</dependency>
JPA Entity example:
package model;
import java.io.Serializable;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlRootElement;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.List;
/**
* The persistent class for the categoria database table.
*
*/
#Entity
#NamedQuery(name="Categoria.findAll", query="SELECT c FROM Categoria c")
#XmlRootElement(name = "categoria")
public class Categoria implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="categoria_id")
private int categoriaId;
private String descripcion;
#JsonIgnore
//bi-directional many-to-one association to Establecimiento
#OneToMany(mappedBy="categoria")
private List<Establecimiento> establecimientos;
public Categoria() {
}
public int getCategoriaId() {
return this.categoriaId;
}
public void setCategoriaId(int categoriaId) {
this.categoriaId = categoriaId;
}
public String getDescripcion() {
return this.descripcion;
}
public void setDescripcion(String descripcion) {
this.descripcion = descripcion;
}
public List<Establecimiento> getEstablecimientos() {
return this.establecimientos;
}
public void setEstablecimientos(List<Establecimiento> establecimientos) {
this.establecimientos = establecimientos;
}
public Establecimiento addEstablecimiento(Establecimiento establecimiento) {
getEstablecimientos().add(establecimiento);
establecimiento.setCategoria(this);
return establecimiento;
}
public Establecimiento removeEstablecimiento(Establecimiento establecimiento) {
getEstablecimientos().remove(establecimiento);
establecimiento.setCategoria(null);
return establecimiento;
}
}
I have two DTO objects say A and B which are having getters and setters and are used to take data from the database. The problem is when I am calling A, B gets called and B again points itself to A and a cycle is created.
I cannot ignore/hide the method which is creating the cycle. I need to take the whole data of A and B.
Is there any way to achieve it ?
Please help
This is my code which is causing the problem. This is application DTO which is calling environment DTO
#OneToMany(mappedBy="application", fetch=FetchType.LAZY
,cascade=CascadeType.ALL
)
public Set<EnvironmentDTO> getEnvironment() {
return environment;
}
public void setEnvironment(Set<EnvironmentDTO> environment) {
this.environment = environment;
}
And this is environment DTO which is calling the application DTO
#ManyToOne(targetEntity=ApplicationDTO.class )
#JoinColumn(name="fk_application_Id")
public ApplicationDTO getApplication() {
return application;
}
public void setApplication(ApplicationDTO application) {
this.application = application;
}
Here cycle is getting created
This is my rest call which will give result in XML format and I think while creating XML cycle is getting created
#GET
#Path("/get")
#Produces({MediaType.APPLICATION_XML})
public List<ApplicationDTO> getAllApplications(){
List<ApplicationDTO> allApplication = applicationService.getAllApplication();
return allApplication;
}
This is the Application DTO class
#Entity
#Table(name="application")
#org.hibernate.annotations.GenericGenerator(
name ="test-increment-strategy",strategy = "increment")
#XmlRootElement
public class ApplicationDTO implements Serializable {
#XmlAttribute
public Long appTypeId;
private static final long serialVersionUID = -8027722210927935073L;
private Long applicationId;
private String applicationName;
private ApplicationTypeDTO applicationType;
private String applicationDescription;
private Integer owner;
private Integer createdBy;
private Integer assignedTo;
private Date createTime;
private Date modifiedTime;
private Set<EnvironmentDTO> environment;
#Id
#GeneratedValue(generator = "test-increment-strategy")
#Column(name = "applicationId")
public Long getApplicationId() {
return applicationId;
}
private void setApplicationId(Long applicationId) {
this.applicationId = applicationId;
}
#Column(name = "applicationName")
public String getApplicationName() {
return applicationName;
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
#ManyToOne(targetEntity=ApplicationTypeDTO.class
,fetch = FetchType.LAZY
)
#JoinColumn(name="applicationType")
public ApplicationTypeDTO getApplicationType() {
return applicationType;
}
public void setApplicationType(ApplicationTypeDTO applicationType) {
this.applicationType = applicationType;
}
#Column(name = "description")
public String getApplicationDescription() {
return applicationDescription;
}
public void setApplicationDescription(String applicationDescription) {
this.applicationDescription = applicationDescription;
}
#Column(name = "owner")
public Integer getOwner() {
return owner;
}
public void setOwner(Integer owner) {
this.owner = owner;
}
#Column(name = "createdBy")
public Integer getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Integer createdBy) {
this.createdBy = createdBy;
}
#Column(name = "assignedTo")
public Integer getAssignedTo() {
return assignedTo;
}
public void setAssignedTo(Integer assignedTo) {
this.assignedTo = assignedTo;
}
#Column(name = "createTime")
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
#Column(name = "modifiedTime")
public Date getModifiedTime() {
return modifiedTime;
}
public void setModifiedTime(Date modifiedTime) {
this.modifiedTime = modifiedTime;
}
#OneToMany(mappedBy="application", fetch=FetchType.LAZY
,cascade=CascadeType.ALL
)
public Set<EnvironmentDTO> getEnvironment() {
return environment;
}
public void setEnvironment(Set<EnvironmentDTO> environment) {
this.environment = environment;
}
This is the Environment DTO class
#Entity
#Table(name="environment")
#org.hibernate.annotations.GenericGenerator(
name = "test-increment-strategy",
strategy = "increment")
#XmlRootElement
public class EnvironmentDTO implements Serializable {
#XmlAttribute
public Long envTypeId;
#XmlAttribute
public Long appId;
private static final long serialVersionUID = -2756426996796369998L;
private Long environmentId;
private String environmentName;
private EnvironmentTypeDTO environmentType;
private Integer owner;
private Date createTime;
private Set<InstanceDTO> instances;
private ApplicationDTO application;
#Id
#GeneratedValue(generator = "test-increment-strategy")
#Column(name = "envId")
public Long getEnvironmentId() {
return environmentId;
}
private void setEnvironmentId(Long environmentId) {
this.environmentId = environmentId;
}
#Column(name = "envName")
public String getEnvironmentName() {
return environmentName;
}
public void setEnvironmentName(String environmentName) {
this.environmentName = environmentName;
}
#ManyToOne(targetEntity=EnvironmentTypeDTO.class)
#JoinColumn(name = "envType")
public EnvironmentTypeDTO getEnvironmentType() {
return environmentType;
}
public void setEnvironmentType(EnvironmentTypeDTO environmentType) {
this.environmentType = environmentType;
}
#Column(name = "owner")
public Integer getOwner() {
return owner;
}
public void setOwner(Integer owner) {
this.owner = owner;
}
#Temporal(TemporalType.DATE)
#Column(name = "createTime")
public Date getCreateTime()
{
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
#OneToMany(mappedBy="environment", cascade=CascadeType.ALL, fetch = FetchType.EAGER)
public Set<InstanceDTO> getInstances() {
return instances;
}
public void setInstances(Set<InstanceDTO> instances) {
this.instances = instances;
}
#ManyToOne(targetEntity=ApplicationDTO.class )
#JoinColumn(name="fk_application_Id")
//#XmlTransient
public ApplicationDTO getApplication() {
return application;
}
public void setApplication(ApplicationDTO application) {
this.application = application;
}
Your object graph is cyclic. There is nothing intrinsically wrong with that, and it is a natural consequence of using JPA.
Your problem is not that your object graph is cyclic, but that you are encoding it in a format which cannot handle cycles. This isn't a Hibernate question, it's a JAXB question.
My suggestion would be to stop JAXB from attempting to marshal the application property of the EnvironmentDTO class. Without that property the cyclic graph becomes a tree. You can do this by annotating that property with #XmlTransient.
(confession: i learned about this annotation by reading a blog post by Mr Doughan, which i came across after reading his answer to this question!)
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
MOXy offers the #XmlInverseReference extension to handle this use case. Below is an example of how to apply this mapping on two entities with a bidirectional relationship.
Customer
import javax.persistence.*;
#Entity
public class Customer {
#Id
private long id;
#OneToOne(mappedBy="customer", cascade={CascadeType.ALL})
private Address address;
}
Address
import javax.persistence.*;
import org.eclipse.persistence.oxm.annotations.*;
#Entity
public class Address implements Serializable {
#Id
private long id;
#OneToOne
#JoinColumn(name="ID")
#MapsId
#XmlInverseReference(mappedBy="address")
private Customer customer;
}
For More Information
http://blog.bdoughan.com/2010/07/jpa-entities-to-xml-bidirectional.html
http://blog.bdoughan.com/2013/03/moxys-xmlinversereference-is-now-truly.html
My advice is not exposing your JPA entity class to your webservices. You can create different POJO class and convert your JPA entity to the POJO. For example:
this is your JPA entity
import javax.persistence.*;
#Entity
public class Customer {
#Id
private long id;
#OneToOne(mappedBy="customer", cascade={CascadeType.ALL})
private Address address;
}
you should use this class for your webservices:
public class CustomerModel{
private long id;
//you can call different WS to get the Address class, or combine to this model
public void setFromJpa(Customer customer){
this.id = customer.id;
}
}
I have the following domain classes:
#Entity
#Table(name="ADDRESSBOOK_FIELD")
#Inheritance(strategy=InheritanceType.JOINED)
public abstract class AbstractAddressbookField {
private int dbID;
private Addressbook addressbook;
public AbstractAddressbookField() {
}
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
return dbID;
}
public void setId(int id) {
this.dbID = id;
}
#ManyToOne
#JoinColumn(nullable=false)
public Addressbook getAddressbook() {
return addressbook;
}
public void setAddressbook(Addressbook addressbook) {
this.addressbook = addressbook;
}
}
.
#Entity
#Table(name="DATE_FIELD")
public class DateField extends AbstractAddressbookField {
public DateField() {
}
}
.
#Entity
#Table(name="NEW_ADDRESSBOOK")
public class Addressbook {
private int dbID;
private Set<DateField> dateFields = new HashSet<DateField>();
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public int getDbID() {
return dbID;
}
public void setDbID(int dbID) {
this.dbID = dbID;
}
#OneToMany(mappedBy="Addressbook", cascade={CascadeType.ALL})
public Set<DateField> getDateFields() {
return dateFields;
}
public void setDateFields(Set<DateField> dateFields) {
this.dateFields = dateFields;
}
}
My packages are being scanned correctly to pick up all the mappings, but I am getting the following exception:
Caused by: org.hibernate.AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class: fields.DateField
I am unsure as to why this is, as the class is clearly mapped to.
Looks like that entity is not mapped in your ' persistence.xml' file.
I think you problem is the capital letter in:
#OneToMany(mappedBy="Addressbook", cascade={CascadeType.ALL})
public Set<DateField> getDateFields() {
return dateFields;
}
use mappedBy="addressbook instead.