How to ignore subclasses in hibernate entities when persisting - java

I have a simple entity class like this
#Entity
public class Car{
#Column protected String name;
}
Everything is ok but now I want to use subclasses or anonymous classes of this entity.
public class TestCar extends Car{
TestCar(){ this.name = "Test"; }
}
or
void foo(){
Car c = new Car(){
{ this.name = "Lone"; }
};
// ...
}
These subclasses are just for instantiation purposes and can be ignored completely by hibernate.
But when I try to save the entity I get an "Unknown entity"-Exception.
Is there a way that hibernate ignores such subclasses?
Edit: It would be nice if we could find an answer to the question. It is not helpful (at least not for me) to discuss all the other (well known) pattern. You should see that this is only a strongly simplified example to clarify the problem. (Probably you should just ignore the use-cases)
Just found this possible duplicate (also no solution): How to persist an entity from an non-entity subclass in Hibernate

It is not going to work.
IMHO you should rethink your design. Is realy TestCar or anonymous Car class a subtype of Car? I think you are using wrong tool for creating instances. You can use Builder pattern.

Related

Design of Comment-Feature for multiple database objects

In my application I have multiple objects that I would like to add comments to. Every one of these objects is represented in its own database table. Beside being connected to a specific object, all comments share a common context in which the corresponding objects exist. What I tried for now is to use JPA-inheritance with InheritanceType.SingleTable so I can store the foreign keys to every 'commentable'-object in one table and the discriminator-feature to seperate that table into different Comment-Subclasses in JPA:
Superclass Comment.java
#Entity
#Table(name = "COMMENT_TABLE")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "COMMENT_OBJECT_TYPE")
public class Comment {
protected String text;
protected CommonContext context;
...
}
Subclass Object A
#Entity
#DiscriminatorValue(value = "OBJECT A")
public class ObjectAComment extends Comment {
private ObjectA objectA;
// OneToMany-Relation exists in Object A accordingly
#JoinColumn(name = "FK_OBJECT_A")
#ManyToOne
public ObjectA getObjectA() { return objectA; }
public void setObjectA(ObjectA objectA) { this.objectA = objectA; }
}
The other comment-classes for the other objects are designed just as for object A. The common context shall be used to get all comments for a specific situation and I would like to have a comment know its owner, so that I can easily link to that object in my application. Without the latter I had to go through all objects of that type to search for any that has comments, as not every object has them.
On designing the REST-endpoints and the EJBs I ended up creating specific methods for every subclass of Comment.java. For example for creating a comment I have
#POST
#Path("comments/objectA")
public Response createCommentForObjectA(ObjectAComment comment) { ... }
#POST
#Path("comments/objectB")
public Response createCommentForObjectB(ObjectBComment comment) { ... }
...
This feels a bit cumbersome as I would rather have
#POST
#Path("comments")
public Response createComment(Comment comment) { ... }
which is impossible with the current design as I would lose the specific information for the different objects. Now I see three possible ways to go on:
Version 1
I stick with the current solution and create CRUD-methods for every type of comment.
Version 2
A friend suggested, that I could use transient properties in Comment.java:
public class Comment {
...
private COMMENT_OBJECT_TYPE objectType;
private long idObject;
#Transient
public long getIdObject() { return idObject; }
...
#Transient
public COMMENT_OBJECT_TYPE getObjectType() { return objectType; }
...
}
With this I could generalize the parameter of the REST-endpoint and return specific objects depending on the object type:
#POST
#Path("comments")
public Response createComment(Comment comment) {
// return ObjectAComment, ObjectBComment, ... depending on the object type
}
Version 3
Ditch the whole #Inheritance and #DiscriminatorColumn, put everything in one JPA-class and do the whole organizing of the comment context myself. Additionaly I would lose type safety.
None of these solutions feels completely right to me, hence I would like to ask if there is a preferable way to design this kind of comment feature and is there maybe something I am missing completely?
Edit 1
Added information that all comments and objects share a common context. Renamed previous COMMENT_CONTEXT to COMMENT_OBJECT_TYPE to avoid a misunderstanding between this common context and the object type a comment is related to.
It seems to me like your Comment is a standalone entity without dependencies on other entities. A comment has an owner, but should not know who is owning it. So I would add a column on the comment table "ownerUuid". The entire comments "bounded context" knows nothing about the other entities.
When creating a comment you always provide the ownerUuid. Same for retrieval. So you can create comments for any entity having a uuid.
However this means you need to add UUID columns in your already existing tables.
This to me seems like the cleanest solution. This way your comment system can stand on it's own without heavy impact on other entities.
EDIT
Because of the extra information. I would suggest following approach.
Keep in mind that I do not know how the owner of the Comment is used, so the suggestion might not be perfect for this scenario.
As the comment should know the owner object I would suggest doing the following:
Have an interface CommentOwner with methods:
getUuid()
getContext()
Any other information you might need from the owner
A Comment will have a CommentOwner property.
Every entity that you want to contain Comments, should implement this interface. When creating a Comment you provide the CommentOwner.
This way you can retrieve comments Based on Context. A Comments has a direct link to its owner, but still does not need to know about the specific classes of the owners.
In the end I went with version 3, keeping every information in one Comment-class. The subclasses which I would've achieved with #Inheritance and #DiscriminatorColumn would only have one property, the foreign key to the commentable object, and wouldn't differ in what they represent in general and how they would be used.
My class looks something like this now:
public class Comment {
private String text;
private CommonContext context;
private COMMENT_OBJECT_TYPE objectType;
private ObjectA objectA;
private ObjectB objectB;
...
#JoinColumn(name = FK_OBJECT_A)
#ManyToOne
public ObjectA getObjectA() { return objectA; }
public void setObjectA(ObjectA objectA) { this.objectA = objectA; }
...
}

Choosing Inheritance Strategy - Hibernate

if this question was aksed here, i surely couldnt find it, or it didnt particulary help me.
i've read some tutorials and some questions for Inheritance Mapping, which couldnt quitely solve my questions.
Say i have an abstract class :
User
And 3 more other subclasses :
UserA, UserB, UserC
those all extend User.
Every Subclass has its own table, Superclass User, meanwhile, doesn't.
In my other class Website i have a ArrayList, or should i say Collections, of Users.
The list should fetch all users of the Website.
Which strategy should i use ? I thought of MappedSuperclass, but since in my Website class the List is of User type, so am not sure what to do here.
Thanks for any help!
With JPA the Java implementation always depends on you own preferences and requirements, sometimes it is the matter of a choice.
Yes, #MappedSuperclass will do.
You can have every child with unidirectional relationship to Website. Then you gonna have Website object inside your User class (with a bunch of annotations), which will map to a database as foreign_key field (presume you are using SQL storage and 'Repositories' DAO abstraction from JPA).
It is not necessary to store a collection of users inside Website class. Just think if you really need it - it can be a mess to support consistency.
But there are cases where you need bidirectional relationship. When you store objects in memory (for caching purposes for example) you'll probably need to have this collection. In this case why not to have 'User' collection? You will fetch data through dedicated repositories(or even if you're not using those, any other way will be using 'User' tables with foreign_key, not the 'Website' table) anyway.
So, for example with the use of Spring Data JPA you can define a unidirectional relationship in a superclass and use 'repositories' next way(and bidirectional example you can find anywhere in the internet, so I am not providing it):
#Entity
public class SuperUser extends User {
...
}
#Entity
public class BasicUser extends User {
...
}
#MappedSuperclass
public abstract class User implements Serializable {
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "website_uuid", nullable = false)
protected Website website;
...
}
#Entity
public class Website implements Serializable {
...
}
#Repository
public interface SuperUserRepository extends CrudRepository<SuperUser, Long> {
Iterable<SuperUser> findByWebsite(Website website);
}
#Repository
public interface BasicUserRepository extends CrudRepository<BasicUser, Long> {
Iterable<BasicUser> findByWebsite(Website website);
}
What you are asking for seems a typical "Table-per-concrete-class" inheritance strategy. https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#entity-inheritance-table-per-class
In older version of the user guide, it has mentioned that separate table will be mapped for each non-abstract classes. In the latest document the "non-abstract" part is not mentioned but I believe it still works similarly.
So it looks something like:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
abstract class User {...}
#Entity
class UserA extends User {...}
#Entity
class UserB extends User {...}
#Entity
class UserC extends User {...}
But you should be aware of this inheritance strategy usually gives inefficient query as internally it is using union.

Is it ok to pass interface of DTO to DAO

It's about passing interface of DTO to DAO.
For example I have following code
public interface User {
String getName();
}
public class SimpleUser implements User {
protected String name;
public SimpleUser(String name) {
this.name = name;
}
#Override
public String getName() {
return name;
}
}
// Mapped by Hibernate
public class PersistentUser extends SimpleUser {
private Long id;
// Constructor
// Getters for id and name
// Setters for id and name
}
I'm using generic DAO. Is it ok if I create DAO with using interface User instead PersistentUser?
User user = new PersistentUser(name);
UserDao.create(user);
I read a lot of topics on stack but not figured out is this approach ok or no. Please help me. Maybe this is stupid and I can achive only problems.
About separating beans.
I did this because some classes I want to share via API module, that can be used outside to create entities and pass them to my application. Because they uses interface I developed so I can pass them to my DAO for persisting.
Generally, I would say it is ok, but there are a few hidden problems. A developer could cast the object down or access some state via a toString method that shouldn't be accessible. If you don't be careful, it could happen that state is serialized as JSON/XML in webservices that shouldn't be serialized. The list goes on.
I created Blaze-Persistence Entity Views for exactly that use case. You essentially define DTOs for JPA entities as interfaces and apply them on a query. It supports mapping nested DTOs, collection etc., essentially everything you'd expect and on top of that, it will improve your query performance as it will generate queries fetching just the data that you actually require for the DTOs.
The entity views for your example could look like this
#EntityView(PersistentUser.class)
interface User {
String getName();
}
Querying could look like this
List<User> dtos = entityViewManager.applySetting(
EntityViewSetting.create(User.class),
criteriaBuilderFactory.create(em, PersistentUser.class)
).getResultList();

JPA entity with a interface attribute, is it possible?

I have the following entity:
#Entity
public class TestCaseStep implements JPAEntity<Integer> {
...
#Column(name="STEP_NUMBER")
private Integer stepNumber;
#Enumerated(EnumType.STRING)
#Column(name="ACTION")
private Action action;
**#ManyToOne
#JoinColumn(name="connector")
private ScriptItem connector;**
My attribute ScriptItem is a interface for 3 other classes. Is it possible to configure JPA to set the correct class id in runtime execution?
Other resources:
public interface ScriptItem {
String getValue();
ScriptItemType getType();
}
#Entity
#Table(name="DAT_FEED_XML")
public class FeedXml implements JPAEntity<Integer>, ScriptItem {
...
}
#Entity
#Table(name="DAT_DB_STMT")
public class DbStatement implements JPAEntity<Integer>, ScriptItem {
...
}
Which annotations should I use to let JPA understand that I want to save the id of one of the 3 classes?
Thanks in advance,
It is really a good idea but unfortunately directly mapping interfaces as an entity attribute is not supported by JPA.
You can only map top level classes directly annotated with #Entity. This top level class may implement an interface though.
This feature has been requested and discussed for a long time.
Also take a look at this and this.
Depending on what you're trying to accomplish, #Inheritance annotation with table-per-class strategy could be an option.
I hope it helps.
It is possible with one caveat - you have to point JPA to a target entity which should be a concrete class. However, it can be an abstract class which implements your interface. So one principle of good design you'll have to break and in particular - "favour composition over inheritance".
Here's how to do it:
In your user class (which references your interface Task):
#OneToOne(targetEntity = BaseTask.class)
private Task task;
so here Task is an interface, but you have to declare an abstract class BaseTask.
In your BaseTask:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="task_type")
#Table(name="Task")
public abstract class BaseTask implements Task{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
}
Here the important thing is #DiscriminatorColumn - since all fields of the inheritance tree will be stored in 1 table (you specified that with the #Inheritance(strategy = InheritanceType.SINGLE_TABLE) annotation above. So this discriminator column will contain a label which will allow JPA to differentiate what kind of task you're talking about
Your concrete classes:
#Entity
#DiscriminatorValue("api")
public class ApiTask extends BaseTask {
or
#Entity
#DiscriminatorValue("ssh")
public class SshTask extends BaseTask{
As you can see the discriminator value tells JPA what task it is going to load (what class to instantiate).
No, not possible with JPA or Hibernate.
It does seem strange, when coding in the Java language which allows for attributes to be interfaces, that a persistence standard like JPA, intended for Java, does not support persisting attributes that are interfaces.
I always found it really very frustrating when my ORM would force me to refactor my 'pure' OO model just so that it could persist it.
It's not that it's technically impossible to implement persisting of interface attributes - in fact JDO has supported persistence of interfaces since forever which is why I started using it years ago for all of my own projects.
I've been tempted to switch to JPA, not because it is technically superior (in fact, quite the opposite) but just because of "herd mentality".
In recent contract work I have been forced to gain experience with JPA/Hibernate and in doing so, have lived out the many limitations and inefficiencies of that combination compared with JDO/DataNucleus. This was a great experience because it helped me quell my desire to join "the herd" :)
You need to setup your inheritance of ScriptItem correctly in JPA using whatever strategy you prefer (see the docs) and then JPA will be smart about it.

Hibernate Component with Generics

Ok, this question is best explained in code. So will try to present the most succinct example I can.
Timestamped.java
#Embeddable
public class Timestamped<E> {
private E value;
private Date timestamp;
...
}
Foo.java
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="TYPE")
public class Foo {
#Embedded
#AttributeOverides({
#AttributeOverride(name="timestamp", column=#Column("VALUE_TS")),
#AttributeOverride(name="value", column=#Column("VALUE"))
})
private TimestampedValue<E> value;
...
}
Bar.java
#Entity
#DiscriminatorValue("BAR")
public class Bar extends Foo<Double> { }
What I need is for Bar to use the appropriate type converter for value.value and a different converter for each subclass of Foo. Ideally I would just like to augment this code, but I would be OK making Foo abstract and moving the value field to each of the subclasses with additional annotations.
The first approach is not going to work - you can't persist "genericized" classes.
You will either have to move value into concrete subclasses like you've suggested OR write a UserType to persist your Timestamped component.
If what you're trying to do is make many classes that correspond to many tables but use the same column names for the 'timestamp' and 'value' properties, then what you want is a 'mapped superclass' with those columns, not an embedded class. Research the #MappedSuperclass annotation.
You are running into an erasure problem. Hibernate cannot know what to do with the generic types, because that information is not available at runtime. It would be nice though.

Categories

Resources