I need to know if it's possible to add some attributes and behaviours to some POJO JPA entity (using hibernate provider) by extending it, and then to make entityManager to return extended objects instead of just pojo entitys, like the following examples:
POJO JPA Entity Class
#Entity
#Table("test")
public class Test implements Serializable {
}
Extended Class
public class ExtendedTest extends Test {
...
}
Fetching Extended Class's objects
List<ExtendedTest> extendedList = entityManager.createNamedQuery("ExtendedTest.findByFoo").setParameter("foo", "bar").getResultList();
The other possible way i'm assessing is extending funcionality with a composite entity and delegating all setters and getters, but this could mean a lot of work with huge tables:
public class ExtendedTest2 {
private Test test;
public ExtendedTest2(Test test) {
this.test = test;
}
public getFoo() {
return test.getFoo();
}
public getBar() {
return test.getBar();
}
...
}
Any suggestions will be very appreciated.
Using #Inheritance
#Entity
#Table(name="TEST")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class Test {
...
}
#Entity
public class ExtendedTest
extends Test {
...
}
or #MappedSuperclass
#MappedSuperclass
public class Test {
...
}
#Entity
public class ExtendedTest
extends Test {
...
}
Related
I am currently defining JPA entities for a legacy database (lots of composite keys, but also single-column keys). I have created the following entity superclass:
#MappedSuperclass
public abstract class AbstractEntity<ID extends Serializable> {
public abstract ID getId();
public abstract void setId(ID id);
}
And then a superclass for composite keys (as well as a superclass for long primary key, not listed here):
#MappedSuperclass
public abstract class AbstractEmbeddedIdEntity<ID extends Serializable> extends AbstractEntity<ID> {
#EmbeddedId
private ID id;
public AbstractEmbeddedIdEntity() {
id = newId();
}
#Override
public ID getId() {
return id;
}
#Override
public void setId(ID id) {
this.id = id;
}
protected abstract ID newId();
}
And finally concrete entities like this:
#Entity
#Table(name = "firstEntity")
public class FirstEntity extends AbstractEmbeddedIdEntity<FirstEntityId> {
public FirstEntity() {
}
#Embeddable
public static class FirstEntityId implements Serializable {
#Column(name = "firstId")
private String firstId;
public FirstEntityId() {
}
#Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof FirstEntityId)) {
return false;
}
FirstEntityId other = (FirstEntityId) obj;
return
Objects.equals(firstId, other.firstId);
}
#Override
public int hashCode() {
return Objects.hash(firstId);
}
}
#Override
protected FirstEntityId newId() {
return new FirstEntityId();
}
}
Now the issue is that if I have multiple entities like this and try to access an ID property of an entity (currently with Spring Boot, e.g. findByIdFirstId(String firstId)), an exception is thrown:
java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [firstId] on this ManagedType [unknown]
I have debugged this and found out that in hibernate, the metamodel maps all of my entities to the same MappedSupperclass instance. During application startup, the #EmbeddedId returned by newId() is set to the MappedSupperclass, overwriting the ID of the previous entity. So in the end, all entities are mapped to the same MappedSupperclass, but the MappedSupperclass only has the #EmbeddedId of the last entity.
In the above example, accessing the ID property fails because the #EmbeddedId of the last entity doesn't have a property called "firstId" (it has been overwritten with the ID properties of the last entity).
Now I am wondering if my approach is wrong, if I am missing something or if this could be an issue with hibernate?
Complete example using spring boot available on github. Run with mvn spring-boot:run.
This looks to me like a bug in hibernate, therefore I have created a ticket in the hibernate bug tracker.
As a workaround I am now defining the ID attribute (#EmbeddedId) in the concreate entity classes instead of the abstract superclass.
My entity class hierarchy is as follows.. ClassB which extends ClassA which extends abstract mappedsuperclass AbstractClass
AbstractClass
#MappedSuperclass
public abstract class AbstractClass implements Serializable
{
}
ClassA
#Table(name = "TABLE_ONE")
#SecondaryTable(name = "TABLE_TWO",
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="Type", discriminatorType=DiscriminatorType.STRING)
#DiscriminatorValue("ClassA")
public class ClassA extends AbstractClass
{
#Column(name = "CLASSA_XML")
private String ClassAXML;
#PrePersist
#PreUpdate
public void covertObjectToXml()
{
this.ClassAXML= JAXBUtilities.marshal(Object);
}
#PostLoad
public void convertXmlToObject()
{
//does unmarshal
}
}
ClassB
#DiscriminatorValue("ClassB")
public class ClassB extends ClassA
{
#Column(name = "CLASSB_XML", table = "TABLE_TWO")
private String ClassBXML;
#PrePersist
#PreUpdate
public void covertObjectToXml()
{
this.ClassAXML= JAXBUtilities.marshal(Object);
}
#PostLoad
public void convertXmlToObject()
{
//does unmarshal
}
}
Problem : when i persist using ClassB entity. ClassA callback methods are not called and value in my classAXml attribute is not persisted.
Is there anyway to generalize callback method(i.e covertObjectToXml and convertXmlToObject) for my inherited entity class structure.. so that when i persist using
both ClassA and ClassB individually, my callback methods are called respectively based on inheritance and their values can be persisted.
Note:
I have removed the callback methods from ClassA and generalize it in
classB and persist but my requirement is mainly individual
persistent of classA and ClassB.
my call back methods should not be in mapedSuperClass i.e AbstractClass.
Thanks in advance
There are two possibilities to reuse the callback code from ClassA in ClassB:
I. The best/most elegant way is to move the whole code to a new class, say MyEntityListeners
and then to use the #EntityListeners annotation on your entity classes like
#EntityListeners(class=MyEntityListeners.class)
public class ClassB extends ClassA {
.....
}
public class MyEntityListeners {
#PrePersist
public void onPrePersist(Object entity) {
//logic with entity (check the class of the entity or you can use `ClassA` instead of `Object`)
}
}
Please note that the EntityListeners are inherited in the subclasses from superclasses, so you do not need to do anything in ClassB if the EntiyListeners are already defined in ClassA (but you can add additional EntityListeners in ClassB, that are not in ClassA). For excluding all EntityListeners from the hierarchy you can use #ExcludeSuperclassListeners
II. If you have less callback methods and a small hierarchy tree, than you could overwrite and re-annotate every callback from ClassA also in ClassB like
...
public class ClassB extends ClassA {
......
#Override
#PrePersist
public void myCallback() {
super.myCallback();
}
......
}
At this moment I start work on small web application based on MVC.
Now I try implement main classes for Model layout using DAO pattern.
So, first of all I create two entity classes (for example): Author and Book:
package myProject.model.entity;
import java.io.Serializable;
public class Author implements Serializable {
private static final long serialVersionUID = 7177014660621405534L;
private long id;
private String firstName;
private String lastName;
public Author() {
}
// getter and setter methods here
}
and Book class:
package myProject.model.entity;
import java.io.Serializable;
public class Book implements Serializable {
private static final long serialVersionUID = 7177014660621405534L;
private long id;
private String title;
private String description;
public Book() {
}
// getter and setter methods here
}
On next step, I see, that classes Book and Author both have getId() and setId().
so, I create interface Persistent for my Entity classes:
package myProject.model.entity;
public interface Persistent {
public long getId();
public void setId(long id);
}
So, first my question:
It is correct implementation for model package?
On the next step, I start implement classes for package dao.
package myProject.model.dao;
import java.util.List;
import myProject.model.entity.Persistent;
public interface Dao {
Persistent get(long id);
void save(Persistent persistent);
void delete(long id);
}
Next step: create interfaces AuthorDao and BookDao, that extend base dao interface Dao
But both interfaces: AuthorDao and BookDao - at this moment empty.
What do you think - it in normal, that interfaces empty? It is my second question.
And on the last step I create package model.dao.hibernate and add to the package to class AuthorDaoHibernate and BookDaoHibernate - both class implements AuthorDao and BookDao interfaces.
And My main question now:
my interface Dao work with objects type Persistent and I dont use Generics. And all ok and nice.
What do you thinks - what benefits I have, if I re-work Dao interface wit Generics:
package myProject.model.dao;
import java.util.List;
import myProject.model.entity.Persistent;
public interface Dao<Persistent> {
T get(long id);
List<T> getAll();
void save(T persistent);
void delete(long id);
}
My Dao classes work only with persistent entities - no any other object type...
Do you really any reasons in me case use Generics?
Generics can greatly improve code readability and reduce errors that could come from wrong casting.
We're using something similar to what you described (note that there are interfaces and implementations needed).
Here's a basic example (I'll leave the getters and setters out for brevitiy):
#MappedSuperClass
class BaseEntity {
#Id
private int id;
}
#Entity
class UserEnity extends BaseEntity {
//user stuff like name
}
class BaseDAO<T extends BaseEntity> {
public T findById(int id) {
...
}
//other generic CRUD methods
}
#Stateless
class UserDAO extends BaseDAO<UserEntity> {
//additional user specific methods
}
Using UserDAO would then be like this:
UserDAO userDao; //some injection or lookup
//no explicit cast needed here, thanks to generics
UserEntity user = userDao.findById(userId);
//compiler error due to the generic parameter being UserEntity and AnotherEntity doesn't extend that
AnotherEntity a = userDao.findById(someId);
If you want to use generics you should define Dao as following:
public interface Dao<T extends Persistent> {
.....................
void save(T persistent);
...................
}
Now when you extend it you will have to create save that accepts Book only:
public class Book extends Dao<Book> {
.....................
void save(Book persistent);
...................
}
The benefit here is that you cannot pass Author to BookDao. This will not pass compilation.
BTW if you are using Hibernate, JPA or other ORM solution you do not really have to create DAO per entity. One generic dao can solve all your needs.
There is no reason here. If it's unique, it's not generic, by definition !
List getAll() will do the Job.
The ArrayList is Generic because it will sometimes return Persistent, sometime President.
I have been looking into JPA/Hibernate #Entity inheritance for a while now and can't seem to find anything that addresses what I am trying to achieve.
Basically I want to be able to define an #Entity with all of the column and table mappings as required. Then I want to be able to extend the #Entity in a number of different locations with different sets of #Transient methods defined in the body of each "sub-Entity". This is a basic example of what I am trying to achieve but with no success thus far:
#Entity
#Table(name = "mountain")
public class MountainEntityBase implements Serializable {
public Integer mountainId = 0;
public Integer height = 0;
public List<ExplorerEntityBase> explorers = new ArrayList<ExplorerEntityBase>();
#Id
#GeneratedValue
#Column(name = "mountain_id")
public Integer getMountainId() { return mountainId; }
public void setMountainId(Integer mountainId) { this.mountainId = mountainId; }
#Column(name="height")
public String getHeight() { return height; }
public void setHeight(String height) { this.height = height; }
#OneToMany(mappedBy="mountainId")
public List<ExplorerEntityBase> getExplorers() { return this.explorers; }
public void setExplorers(List<ExplorerEntityBase> explorers) { this.explorers = explorers; }
}
.
#Entity
public class MountainEntity extends MountainEntityBase implements Serializable {
public List<MountainEntity> allMountainsExploredBy = new ArrayList<MountainEntity>();
#Transient
public List<MountianEntity> getAllMountainsExploredBy(String explorerName){
// Implementation
}
}
So any extended class will define only #Transients in its body. But also I want to allow for situations where the child class is empty:
#Entity
public class MountainEntity extends MountainEntityBase implements Serializable {
}
Thanks in advance for any help with this.
Inheritance in JPA is specified on the root entity using the #Inheritance annotation. There you can specify the database representation of the hierarchy. Check the documentation for more details.
If your child classes define only transient fields (not methods) (i.e. not saved in the db), then perhaps a discriminator column is the best option. But it may be the case that you don't actually need inheritance - the main entity can have all the methods (because it has all the fields the methods operate on)
Dynamic Inheritance
I have a situation where I want a class (which is a JPA entity) to be able to extend either class A or class B dynamically. My thought was to use Generics, but it looks like generics doesn’t support this. For example:
#Entity
public abstract class Resource() {
...
}
#Entity
public abstract class Snapshot() {
...
}
public abstract class CommonRS<R extends Resource, S extends Snapshot> {
/* This is the class that I want to dynamically assign Inheritance to. */
...
}
#Entity
public class FeedResource extends CommonRS<Resource> {
...
}
#Entity
public class FeedSnapshot extends CommonRS<Snapshot> {
...
}
The reason I want to do this is that FeedResource must Inherit from Resource and FeedSnapshot must inherit from Snapshot because both classes are using the JPA join strategy InheritanceType.JOINED and are persisted to different tables, however they both share common attributes and I would like them to be able to inherit those common attributes.
I understand that I can I could use #Embeddable on CommonRS and the Embed it in both FeedResource and FeedSnapshot.
Since Java doesn’t support multiple inheritance, I can’t see any other way to do this other than using Embeddable.
Thanks in advance.
Here is how you do it
#MappedSuperClass
public abstract class Base() {
...
// put your common attributes here
}
#Entity
public abstract class Resource() extends Base{
...
}
#Entity
public abstract class Snapshot() extends Base {
...
}
public abstract class CommonRS<R extends Base> {
...
}
#Entity
public class FeedResource extends CommonRS<Resource> {
...
}
#Entity
public class FeedSnapshot extends CommonRS<Snapshot> {
...
}
UPDATE
Another solution can be implementing same interface (if common inheritance cannot be achieved). In that case #MappedSuperClass annotation should be used on actual base classes.
#Entity
public abstract class Resource() extends BaseIntf {
...
}
#Entity
public abstract class Snapshot() extends BaseIntf {
...
}
public abstract class CommonRS<R extends BaseIntf> {
...
}
#Entity
public class FeedResource extends CommonRS<Resource> {
...
}
#Entity
public class FeedSnapshot extends CommonRS<Snapshot> {
...
}