Here is the example code:
class Resource {
Long id;
#Embedded
GPU gpu;
CPU cpu;
}
abstract class GPU {
String name;
GpuType type;
}
class PhysicalGPU extends GPU {
}
class VirtualGPU extends GPU {
private int partition;
}
I have an Entity Resource and it has a field GPU which is a superclass. It can be a VirtualGPU or PhysicalGPU. But JPA or Hibernate seems not support class inheritance for #Embedded fields. And it is ugly to create a single GPU type with no inheritance or create PhysicalGPUResource and VirtualGPUResource to implement the inheritance for a single field.
And I think as a descriptor of a Resource, make the GPU be an association in a seperate table (and give a ManyToOne relation in Resource) is also not a good practice but this will make the Inheritance available.
I did some search and I think right now the answer is no. But I still think this is a quite big requirement for the Hibernate ORM and it can be implemented in some framework like MyBatis, it is quite weird that Hibernate do not support this behavior. So maybe there is some other way to make this done?
I think current the best way is using UserType. Follow the article Custom Types in Hibernate and the #Type Annotation can be very helpful.
But I still don't know what is the advantage of the CompositeUserType.
Related
I decided to use single table inheritance which results in having multiple classes and I can't access the child's fields through a parent object in the view part of the application. So far I didn't find a nice solution how to deal with it in Thymeleaf. What does it mean?
Before I split my classes to use single table inheritance I could easily pass 1 object class that contained all the information needed to create or display the object but it had too many fields that would be null. With multiple classes thymeleaf doesn't really allow you to cast objects to a different type(and from what I understand it wouldn't be a good practice to do that in a view part of the application). So what is really the best way to deal with this problem?
I can come up with ideas like:
Create a DTO that contains the fields from all the classes and transform the objects to this class, it would be great in a create-view (POSTing DTO and then creating an object from it and adding to the database). But if I used this method for displaying information then it would mean casting each of the objects to a DTO class which kind of misses the point of single table inheritance in my opinion. I feel like this is too similar to going back to no inheritance at all.
Passing multiple objects or a parent object + a different object that would hold the rest of the information that the parent class doesn't hold. This also seems kind of weird.
Adding one method to a parent class per sub-class additional field and overwrite them in the sub-classes to return actual values while parent would return null. Not sure if this would fix the problem of creating the objects from a view though.
Let's assume this example with three simple classes where Person is a parent class and Client and Employee are children of it. I will skip getters, setters and constructors for simplicity.
Person main class that holds shared fields
#Entity
#Inheritance
#DiscriminatorColumn(name = "person_type", discriminatorType = DiscriminatorType.STRING)
public abstract class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
int personId;
int age;
String name;
}
Client class that extends person with additional field favouriteProduct
#Entity
#DiscriminatorValue(value= "CLIENT")
public class Client extends Person {
String favouriteProduct;
}
Employee class that extends person with additional fields salary and position.
#Entity
#DiscriminatorValue(value= "EMPLOYEE")
public class Employee extends Person {
String position;
int salary;
}
Given this simple structure I would like to create Employee and Client objects through a single form via a POST request and also display them together in a different view with their fields that are unique to each subclass. Problem is that I would need to pass an object that holds all the fields to the view to actually make it work which comes back to the problem and solutions that I came up with. Is there any correct way or best practice how to deal with this? I thought DTOs should rather scale down from full objects to objects with less fields.
Conclusion: if the answer isn't really that simple then what is really the use of single table inheritance in this case and why isn't it a good idea to just go back to 1 table implementation? I already know about polymorphic queries and it is a nice bonus but so far I can't really deal with the problem I explained above. Thanks in advance!
I don't know about Thymeleaf (sorry!), but I do know about object-oriented programming a bit. Leaving frameworks aside and talking from a pure OO perspective, parent classes know nothing about their children (inheritors). Only the opposite can be true, and that's if you use the appropriate access modifiers. Given that said, I believe you can not do what you want unless there is some ugly framework black magic going under the hood haha.
Suppose I have already made class which I wish to persist. I can't change it's code, i.e. can't put any annotations inside. Also, class is not following bean convention.
I.e. it is arbitrary complex class I wish to persist.
Is it possible to write some sort of custom serializer and deserializer (don't know how to name it) in Hibernate, so that I be able to read these classes as usual POJOs?
Hello the first question is can I map a "fina class" the answer to this question is YES as long as you dont use Hibernate Enchancing or some sort of instrumentation.
Now second question. Bean not following Bean Conventions. I guess this means no getters and setters. You can have Attribute level access so this is again not a problem.
Is it possible to write custom serializer in Hibernate. The answer here is NO. Why ? Because Hibernate is not about Serialization hibernate is about SQL. There is no strict requirement that a Hibernate Entity should be serialize-able.
Even though Hibernate does not enforce serialization. Can I still make my final class serialize-able even though it does not implement Serializable or Eternalizeable. Yes you need to wrap it into class implementing Serializable or Externalizeable and implement the doRead doWrite methods yourself.
Serialization to JSON or XML - this is not part of Hibernate neither is part of JPA. Serialization to these two formats is defined as part of the Jaxb and Jax-rs specifications.
Have a look at hibernate UserType and CompositeUserType, with the well known EnumUserType example
Enums are a bit like your needs : final class, no getters nor setters. They are not complex though, so you might need a CompositeUserType that allows to map several columns for one Type, rather that a UserType.
Then you would use it like that in your class :
public class MyClass {
#Id
private Long id;
#Type(type = "com...MyCompositeUserType")
private ComplexFinalClassNotPojo complexObject;
}
I need to create a database with 2 kinds of 'modules'.
domain focused classes
metadata classes
In the first group it is just simple (or complex rather) RDBMS. The second 'block' are metadata classes which collects information about classes from the first block.
What I have done:
Created Entity class which is parent of all fro 1st part:
#PersistenceAware
#Inheritance(strategy = InheritanceStrategy.NEW_TABLE)
public abstract class Entity implements Serializable {
private static final long serialVersionUID = 1L;
}
Created normal schema with all entities inherit somehow Entity class.
Created InternalMapping class as a parent of the whole concept.
#PersistenceCapable
#Inheritance(strategy = InheritanceStrategy.NEW_TABLE)
public abstract class InternalMapping implements Serializable {
private static final long serialVersionUID = 1L;
private Entity entity;
//.. cut off getter and setter
}
Created InternalMapping child which should have that feature.
Finally I found it does not work. Probably because Entity does not have any field. But if so I would expect 2 fields: a primary key and class name. In that way I would map every entity by 2 coordinates: ID and class name.
Any idea how to solve that issue? An finally how JDOQL would looks like.
Ps. I know that RDBMS is not the best solution for that kind of problems but people with whom I work wish to have relational database.
Finally I found solution for my problem. I am able to keep entities of different classes keep in one table. Also I am able to do JDOQL request with filtering instances of particular class.
The example is inside GitHub repository here: https://github.com/jgrzebyta/samples-jdo/tree/metalink and within metalink branch. It is slightly modified Tutorial project from datanucleus example.
So.
The lowest level in the inheritance hierarchy is Core interface with the PK defined inside.
Class MyIndex collects different implementations of the Core interface, i.e. Book and Product. Also I have added new column called type for storing Class names only. I am able to retrieve implementations of Core interface and build query filter against type filed because query type core instanceof Book simple does not work. That is the feature of the identity mapping strategy which I have used in my solution: DataNucleus JDO Objects.
PS. If you run command mvn -Pschema-gen compile than you will receive DDL file.
lets say i have the following POJO Class
public class Example {
private String name;
private int id;
private Object o;
// more fields
// getter/Setter
Now lets assume i want to persist my Entity using JPA i will come on with the following example POJO Class:
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int id;
#OneToMany(mappedBy = "directive")
private String name;
In my Opinion this is bad, becaus if i want to use e.g. Spring Data MongoDB the Annotations would be useless/false.
The only why i can think of to avoid this, is defining an Interface or an Abstract class, for example Storable, which defines getter/setter methods.
But then i have violated the POJO definition (and one can argue it was not a Pojo to begin with).
Are there any best Practices for defining Model Classes?
When using JPA, you can leave you classes untouched and have ALL your configuration in XML files. Many people prefer annotations, but if changing the persistence implementation is a requirement, you should consider using external configuration.
I am not sure about other frameworks/specs besides JPA, but XML configuration goes a long way in java. I am sure, many frameworks offer such possibilities.
There is also a pattern called DTO (data transfer objects) that can be used for separation of persistence concerns from business concerns.
The gist is: you use your annotated, DB-centric classes for your DB connection only. Your main application only uses business-oriented classes and is persistence-agnostic. The data could come from a DB or from a flat file, as long as you can convert it to you business objects, all is well.
EDIT: DTOs sound like a lot of work, but you gain clarity and testability by separating concerns. hexagonal architecture and clean architecture emphasize this approach.
I have domain objects that are stored in both HBase and PostgreSQL.
While defining the class the annotations used for PostgreSQL are not applicable to HBase, so I end up defining two classes with the same properties but different annotations. I use Hibernate/Spring framework.
For PostgreSQL, the domain class I use is as below: (snippets)
#Entity
#Table(name="foo_bar")
public class FooBarPgsql implements Serializable {
private static final long serialVersionUID = 5848293352035620189L;
#Id
#Column(name="id")
String id;
#Column(name="name")
String name;
}
for HBase, the class is:
public class FooBarHbase {
String id;
String name;
}
So, If I had to use a single class for both PostgreSQL and HBase, how should I define the class?
I think your combined class is going to be more complicated than two classes with a common interface (which can be dispatched as necessary). The databases are just so different, and HBase is not really compatible with ORM approaches.
I think you will get more bang for your buck with careful use of composition and the like than you will out of trying to fully merge the classes. Since Java can dynamically alter class properties, trying to centralize code in this way is more likely to allow you a clean set of classes for delegating the actual database handling.
You can probably do this if you really really want, but I am not sure it will be worth it in terms of the cost it will certainly take in terms of code quality. Let details depend on interfaces, not the other way around.