I am new with JPA, so maybe someone can explain me how to correctly annotate abstract classes using JPA?
I have an abstract class with generated id field:
public abstract class AbstractClass implements Serializable {
private static final long serialVersionUID = 1L;
private long id;
#Id
#GeneratedValue
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
and an abstract class with name which extends AbstractClass:
public abstract class AbstractNameClass extends AbstractClass {
private String shortName;
#Column(name = "shortName", nullable = false)
public String getShortName() {
return shortName;
}
public void setShortName(String shortName) {
this.shortName = shortName;
}
}
I have two types of classes, one extends AbstractClass and other classes extends AbstractNameClass:
#Entity
public class Model extends AbstractNameClass {
// this class should inherit id (from AbstractClass) and shortName (from AbstractNameClass)
}
and
#Entity
public class Vehicle extends AbstractClass {
// this class should inherit only id
}
If I add #MappedSuperclass annotation on AbstractClass, then I can create and save objects which are extending AbstractClass, but how to annotate AbstractNameClass? I tried to add #Entity annotation, but I got "No identifier specified for entity" error, also I tried to add #MappedSuperclass annotation and also got the same error.
So my question would be - how to correctly annotate abstract classes using JPA, without creating AbstractClass and AbstractNameClass tables (in my db I want to have only Model and Vehicle tables)?
I have two classes.
One class extends the other.
Both classes will be persisted in the database.
Why am I still getting : Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.ct.www.model.Bt column: q_Id (should be mapped with insert="false" update="false")
Questions.class
#Entity
#Table(name="Questions")
#Access(value = AccessType.FIELD)
public class Questions implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
//#Access(value= AccessType.FIELD)
private String q_Id;
#Column(name="q_type")
private String q_Type;
#Column(name="q_lang")
private String q_lang;
#Access(value = AccessType.PROPERTY)
public String getQ_Type() {
return q_Type;
}
public void setQ_Type(String q_Type) {
this.q_Type = q_Type;
}
#Id
#Column(name="q_Id")
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Access(value = AccessType.PROPERTY)
public String getQ_Id() {
return q_Id;
}
public void setQ_Id(String q_Id) {
this.q_Id = q_Id;
}
#Access(value = AccessType.PROPERTY)
public String getQ_lang() {
return q_lang;
}
public void setQ_lang(String q_lang) {
this.q_lang = q_lang;
}
}
BT.class
#Entity
#Table(name="BT")
#Access(value = AccessType.FIELD)
public class BT extends Questions implements Serializable{
private static final long serialVersionUID = 1L;
#Access(value = AccessType.FIELD)
// #Id
// #Column(name="q_Id")
private String q_Id;
#Access(value = AccessType.PROPERTY)
public String getQ_Id() {
return q_Id;
}
public void setQ_Id(String q_Id) {
this.q_Id = q_Id;
}
// #OneToOne(cascade = CascadeType.ALL)
// #PrimaryKeyJoinColumn
// #JoinColumn(name="q_id")
// #MapsId
private Questions question;
public Questions getQuestion() {
return question;
}
public void setQuestion(Questions question) {
this.question = question;
}
}
One of my use case is
Questions and BT will be persisted separately into corresponding tables in MySQL (Questions table and BT table).
BT is a type of Question. So I decided to extend it.
Both table has a primary key which is Id, and my DAO class will first insert in Questions table and use same Id for BT class which later inserts into BT table.
Extending a base class which is an Entity will cause this problem.
You can:
Remove the common mapped fields/properties from the child class
Add #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) above parent class for your use case.
Refer to Section 2.11.4 in Hibernate-5.3.1.Final User Guide for example code.
If you need different generation strategy in parent and child, you can override the getQ_Id() method in child and implement that.
I have a database with common audit columns in each table but with different column names.
e.g
The Person table has the following audit columns,
(per_creation_user, per_creation_date, per_update_user, per_update_date), and the address table has audit columns called (add_creation_user, add_creation_date, add_update_user, add_update_date).
I am trying to map these using JPA annotations and use an event listener class to populate these audit columns automatically whenever they are persisted in the database.
I have a base abstract class containing these audit columns, I could then annotate this with #MappedSuperclass and put the entity listener annotation on here too. All neat and tidy, unfortunately the column names differ for each audited entity. I think the only option is to have the audit columns mapped separately on each entity?
Can anybody suggest a better method for doing this?
#EntityListeners(BaseDTOEventListener.class)
#MappedSuperclass
public abstract class BaseDTO {
private String creationUser;
private Date creationDate;
}
#Entity
#Table(name="PERSON")
public class Person extends BaseDTO{
}
#Entity
#Table(name="ADDRESS")
public class Address extends BaseDTO{
}
public class BaseDTOEventListener {
#PrePersist
public void onPreInsert(BaseDTO baseDTO){
baseDTO.setCreationUser("TEST");
baseDTO.setCreationDate(new Date());
}
}
Thanks to Alan for the hint, by specifying column names on each object as below. This worked :)
#Entity
#AttributeOverrides({#AttributeOverride(name="creationUser", column=#Column(name="PER_CREATION_USER", insertable=true, updatable=false)),
#AttributeOverride(name="creationDate", column=#Column(name="PER_CREATION_DATE" insertable=true, updatable=false})
#Table(name="PERSON")
public class Person extends BaseDTO{
}
Use the #Embeddable in combination with #MappedSuperClass:
First define the BaseDTO interface:
#EntityListeners(BaseDTOEventListener.class)
#MappedSuperclass
public abstract class BaseDTO {
public abstract getAuditEmbeddable();
public void setCreationDate(Date date){
getAuditEmbeddable().setCreationDate(date);
}
public void setCreationUser(String user){
getAuditEmbeddable().setCreationUser(user);
}
}
Then define the embeddable which will hold the audited fields.
User most common column names here.
#Embeddable
public class AuditEmbeddable{
#Column(name = "creationUser")
private String creationUser;
#Column(name = "creationDate")
private Date creationDate;
public String getCreationUser() {
return creationUser;
}
public void setCreationUser(String creationUser) {
this.creationUser = creationUser;
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
}
Then you inject an embedded to each of the audited entities, overriding the column names where necessary:
#Entity
#Table(name="PERSON")
public class Person extends BaseDTO{
#Embedded
private AuditEmbeddable auditEmbeddable;
public AuditEmbeddable getAuditEmbeddable() {
return auditEmbeddable;
}
public void setAuditEmbeddable(AuditEmbeddable auditEmbeddable) {
this.auditEmbeddable = auditEmbeddable;
}
}
#Entity
#Table(name="ADDRESS")
public class Address extends BaseDTO{
// lets say here you have custom names for audit fields
#Embedded
#AttributeOverrides(
#AttributeOverride(name = "creationUser", column = #Column(name = "creationUser123")),
#AttributeOverride(name = "creationDate", column = #Column(name = "creationDate123"))
)
private AuditEmbeddable auditEmbeddable;
public AuditEmbeddable getAuditEmbeddable() {
return auditEmbeddable;
}
public void setAuditEmbeddable(AuditEmbeddable auditEmbeddable) {
this.auditEmbeddable = auditEmbeddable;
}
}
Finally the listener can stay as you wrote it:
public class BaseDTOEventListener {
#PrePersist
public void onPreInsert(BaseDTO baseDTO){
baseDTO.setCreationUser("TEST");
baseDTO.setCreationDate(new Date());
}
}
Hope that helps.
You can use hibernate envers for the same purpose. You can annotate with #Audited. Apply #NotAudited to the entities you do not want to be
#Entity
#Table(name="PERSON")
#Audited
public class Person extends BaseDTO{
}
#Entity
#Audited
#Table(name="ADDRESS")
public class Address extends BaseDTO{
}
I'm building RESTful service on java using JERSEY and need to implement relationships between entities storing just identifier on another entity not whole. Is there any way to implements it in the hibernate?
I'm using something like this but it is not working.
#Entity
#javax.persistence.Table(name = "manager_user")
public class ManagerUser extends User {
#ManyToOne(targetEntity = ShopAdminUser.class)
private Integer shopAdminUserId;
//...
}
#Entity
#javax.persistence.Table(name = "shop_admin_user")
public class ShopAdminUser extends User {
#Lob
private String contactData;
public String getContactData() {
return contactData;
}
public void setContactData(String contactData) {
this.contactData = contactData;
}
}
#Entity
#Inheritance(strategy= InheritanceType.TABLE_PER_CLASS)
public abstract class User {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
private Integer id;
//...
}
It will be very comfortable for me to implement this.
I'm working on Hibernate and i need two abstract classes. First one, Product is the main one and there should be no table on the database named product. Second abstract class is ComPart(inherited from Product) and some computer parts like gpu and cpu are inherited from this class. There should be only one table named com_part and both CPUs and GPUs should be in this table(table per hierarchy).
#MappedSuperclass
public abstract class Product{
private long pID;
protected String manufacturer;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "PID", unique = true, nullable = false)
public int getPID() {
return pID;
}
#Column(name = "Manufacturer")
public String getManufacturer() {
return manufacturer;
}
}
// computer part abstract class inherited from Product
#Entity
#Table(name = "com_part")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(
name="disc",
discriminatorType=DiscriminatorType.STRING
)
#AttributeOverrides({
#AttributeOverride(name="manufacturer", column=#Column(name="Manufacturer"))
})
public abstract class ComPart extends Product {
private String platform;
#Column(name = "PLATFORM", length = 10)
public String getPlatform() {
return platform;
}
}
// Various computer hardwares inherited from ComPart
#Entity
#Table(name="com_part")
#DiscriminatorValue("CPU")
public class Processor extends comPart {
private String socketType;
private String chipset;
//getters setters...
}
#Entity
#Table(name="com_part")
#DiscriminatorValue("GPU")
public class GraphicsCard extends comPart {
private double memory;
//getters setters...
}
How can i map all these features? Above code even can't create sessionfactory?! it generates these errors:
Failed to create sessionFactory object.java.lang.NullPointerException
Exception in thread "main" java.lang.ExceptionInInitializerError
at com.bts.core.hb.HibernateUtil.<clinit>(HibernateUtil.java:35)
and
Caused by: java.lang.NullPointerException
at org.hibernate.cfg.Configuration.processFkSecondPassInOrder(Configuration.java:1424)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1351)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1733)
at com.bts.core.hb.HibernateUtil.<clinit>(HibernateUtil.java:32)