How to define a generic primary key field in base entity? - java

I have created a BaseEntity class which will have all the common fields of the other entities like created_date, created_by, updated_by etc., I also kept primary key id in there. I am using extends and using the fields from base entity class. The main problem is id field is of type Long in some entities and type of String in some other entities, so how can I manage the id field?
Base Entity Class:
#Getter
#Setter
#MappedSuperclass
public abstract class BaseEntity implements Serializable {
private static final long serialVersionUID = 3779027956207925319L;
protected Long id;
private String createdBy;
private Date createdDate;
private String lastUpdatedBy;
private Date lastUpdatedDate;
private Boolean isActive;
public abstract Long getId();
public abstract void setId(Long id);
#Override
public String toString() {
return String.format(
"BaseEntity [createdBy=%s, createdDate=%s, lastUpdatedBy=%s, lastUpdatedDate=%s, isActive=%s]",
createdBy, createdDate, lastUpdatedBy, lastUpdatedDate, isActive);
}
}

Have a generic base entity, where generic type defines the type of your id column;
#Getter
#Setter
#MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
protected T id;
// fields, constructors, methods etc
}
When you have an entity where id is of type Long, extend with that type;
#Entity
public class TableWithLongId extends BaseEntity<Long> {
// fields, constructors, methods etc
}
or when you need a String type id;
#Entity
public class TableWithStringId extends BaseEntity<String> {
// fields, constructors, methods etc
}

Modify your getter and setter, use parsing in them so that they get long data and give String data, or vice versa accordingly.

Related

JPA how to annotate generic entity field conditionally?

I have this generic entity:
#MappedSuperclass
abstract class Position<T> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Enumerated(EnumType.STRING)
private T name;
}
But there's a case where the generic type is a String:
#Entity
class ChildPosition0 extends Position<String> {
}
And, JPA will complaint that String is not an enum in this case, but I need to annotate this name field if it's an enum, if not, the database will mark it as int type, and that's not ideal. How do I solve this? How to annotate the field conditionally?
My workaround:
Use Position as a parent class, and adding those field in child class individually, even though they share the same field:
#MappedSuperclass
abstract class Position {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
}
And extends it from child entity like this:
Child1:
#Entity
public class ChildPosition1 extends Position {
#Enumerated(EnumType.STRING)
private Priority name; // <- Priority is enum type
}
Child2:
#Entity
public class ChildPosition2 extends Position {
private String name;
}
This is too ugly IMO. And Java does not allow class field override from child class. So, back to the question: how to annotate generic field conditionally?

What is correct way to annotate abstract classes inheriting each other using JPA?

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)?

Duplicate generator sequence hibernate on subclasses

I follow this post to resolve my initial problem:
Specifying distinct sequence per table in Hibernate on subclasses
But now I get an exception:
Invocation of init method failed; nested exception is
java.lang.IllegalArgumentException: Duplicate generator name idgen
Below my class, subclass and pom.xml:
EntityId (abstract class)
#MappedSuperclass
public abstract class EntityId<T extends Serializable> implements Serializable {
private static final long serialVersionUID = 1974679434867091670L;
#Id
#GeneratedValue(generator="idgen", strategy=GenerationType.SEQUENCE)
#Column(name="id")
protected T id;
public T getId() {
return id;
}
public void setId(T id) {
this.id = id;
}
}
Category class
#Entity
#SequenceGenerator(name="idgen", sequenceName="cat_id_seq", allocationSize=1)
#AttributeOverrides({
#AttributeOverride(name="id", column = #Column(name="cat_id"))
})
#Table(name="categoria")
public class Category extends EntityId<Integer> {
private static final long serialVersionUID = -870288485902136248L;
#Column(name="name")
private String name;
#Column(name="description")
private String description;
}
pom.xml
...
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.15.Final</version>
</dependency>
...
My problem it's similar with this post: https://hibernate.atlassian.net/browse/HHH-12329
From the link you provided. The JPA spec says that:
A sequence generator may be specified on the entity class or on the
primary key field or property. The scope of the generator name is
global to the persistence unit (across all generator types).
So, it's not legal to have two identifier generators with the same name and different configurations. The scope is global, not entity.
To resolve your issue you should push the #Id from the #MappedSuperclass into subclasses.
More details
Edited, added possible workaround:
remove annotation from field in super class;
make getter abstract;
let all sub-classes have their own sequence generator: all generators should have global unique name;
implement getter;
move annotations related to Id field on getter.
public interface EntityId<T extends Serializable> extends Serializable {
public T getId();
public void setId(T id);
}
#Entity
#Table(name="categoria")
public class Category implements EntityId<Integer> {
private static final long serialVersionUID = -870288485902136248L;
#Id
#Column(name="cat_id")
#SequenceGenerator(name="cat_id_gen", sequenceName="categoria_cat_id_seq", allocationSize=1)
#GeneratedValue(generator="cat_id_gen", strategy=GenerationType.SEQUENCE)
private Integer id;
//others attributes here...
#Override
public void setId(Integer id) {
this.id = id;
}
#Override
public Integer getId() {
return this.id;
}
}

How to query jpa entity in JOINED inheritance, without creating table for same?

I am trying to implemet inheritance hierarchy as mentioned in below image using hibernate Joined strategy.
Since Joined strategy creates table for entity regardless of entity class is Concrete or Abstract.
I don't want to create separate table for "CompanyEmployee" so I declared it as mapped superclass, but I should able to query this class/subclasses in polymorphic way.
Since it is mapped superclass I can't do this, and if I declare it to be entity it will create table which I want to avoid.
So, is there any way I can achieve this? I am thinking about mixed inheritance but from below quote it doesn't seems to be a good solution.
Mixed Inheritance
We should begin this section by saying that the practice of mixing inheritance types within a single
inheritance hierarchy is currently outside the specification. We are including it because it is both useful
and interesting, but we are offering a warning that it might not be portable to rely on such behavior,
even if your vendor supports it.
Inheritance hierarchy
#Entity
#Table(name="j_employee")
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="emp_type", discriminatorType=DiscriminatorType.STRING)
public abstract class JEmployee extends AuditLog implements Serializable {
#Id
#Basic
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="employee_id")
private Integer employeeId;
#Basic
#Temporal(TemporalType.DATE)
#Column(name="join_date")
private Date joinDate;
#OneToOne
#JoinColumn(name="person_id", nullable=false)
private Person person;
#Column(name="emp_type", updatable=false, insertable=false)
private String empType;
//Getters and Setters
}
#Entity
#Table(name="j_contract_employee")
#DiscriminatorValue(value="JContractEmployee")
#PrimaryKeyJoinColumn(name="contract_employee_id", referencedColumnName="employee_id")
public class JContractEmployee extends JEmployee implements Serializable {
#Basic
#Column(name="daily_rate")
private Integer dailyRate;
#Basic
#Column(name="term")
private Integer term;
//Getters and Setters
}
//Don't want to create table for this class, but I should able to query this clas/subclasses in polymorphic way
#MappedSuperclass
public abstract class JCompanyEmployee extends JEmployee implements Serializable {
#Basic
#Column(name="vacation")
private Integer vacation;
//Getters and Setters
public Integer getVacation() {
return vacation;
}
public void setVacation(Integer vacation) {
this.vacation = vacation;
}
}
#Entity
#Table(name="j_part_time_employee")
#Access(AccessType.FIELD)
#DiscriminatorValue(value="JPartTimeEmployee")
#PrimaryKeyJoinColumn(name="part_time_employee_id", referencedColumnName="employee_id")
public class JPartTimeEmployee extends JCompanyEmployee implements Serializable {
#Basic
#Column(name="hourly_rate")
private Integer hourlyRate;
//Getters and Setters
}
#Entity
#Table(name="j_full_time_employee")
#Access(AccessType.FIELD)
#DiscriminatorValue(value="JFullTimeEmployee")
public class JFullTimeEmployee extends JCompanyEmployee implements Serializable {
#Basic
#Column(name="salary")
private Integer salary;
#Basic
#Column(name="penion")
private Integer pension;
//Getters and Setter
}

Any way to apply sort of a JPA AttributeConverter over an Embeddable class?

I'd like to post-process my embeddable class to convert it to another type
#Embeddable
public class Identity {
private Long id;
private String alias;
}
#Embeddable
public class virtualIdentities {
private Long id;
private List<String> aliases; //AttributeConverter applied from a ","-joined string
}
#Entity
public class Parent {
private Identity identity; //Works flawlessly
private VirtualIdentities vIdentities; //Works flawlessly but...
private List<Identity> vIdentities; //<- That is what I'd like to achieve!!
}
So I am looking for a mechanism (standard JPA preferrably) that allows me to map someway a VirtualIdentities embeddable instance as a List<Identity>
If only I could do AttributeConverter<List<Identity>,VirtualIdentities> ...

Categories