How to map parent's bean class variable in Hibernate? - java

I have a Bean class called Bean_A that is map to table_A, and this Bean_A class is inherited from a base bean class, and the base bean class will have a unique_reference_key variable that will going to save into the database together with the Bean_A class. I already have the hibernate file ready for the Bean_A and the unique_reference_key field in table_A.
May I know how could I map the base bean class in hibernate to ensure this unique_reference_key variable is save into database when I was saving the Bean_A object? Take note that this base bean class is not map to any table in database, and there is no such table that "represent" the base bean.
Before I throw out this question, I have consult the following article but still couldn't get any clue on it.
Hibernate simplifies inheritance mapping
Hibernate Chapter 5.Basic O/R Mapping

Your descriptiin would be much clearer if you added some code. But I think you're just looking for the MappedSuperclass annotation, described in the documentation:
5.1.6.4. Inherit properties from superclasses
This is sometimes useful to share common properties through a
technical or a business superclass without including it as a regular
mapped entity (ie no specific table for this entity). For that purpose
you can map them as #MappedSuperclass.
#MappedSuperclass
public class BaseEntity {
#Basic
#Temporal(TemporalType.TIMESTAMP)
public Date getLastUpdate() { ... }
public String getLastUpdater() { ... }
...
}
#Entity class Order extends BaseEntity {
#Id public Integer getId() { ... }
...
}

I have found the solution on how to map the base bean property into Bean_A in hibernate.
In hibernate:
<class name="com.dao.pojo.BaseBean" abstract="true">
<id name="theId" type="string">
<column name="primary_key" length="15" />
</id>
<property name="unique_ref_key" type="java.lang.String" column="unique_ref_key"/>
<union-subclass name="com.dao.pojo.Bean_A" table="table_A" lazy="false">
...
</union-subclass>
</class>
Please note that theId was originally from Bean_A and it has been move to BaseBean. A new field, unique_ref_key, is created inside table_A.
In JAVA:
public abstract class BaseBean {
private String theId;
private String unique_ref_key;
// getter and setter
}
public class Bean_A extends BeseBean {
...
}
Hope this solution can help others.

Related

How to dynamically create extra fields to all annotated models through hibernate?

I have a set of POJO classes with its hibernate xml definitions. I'm now trying to add two new fields 'createdDate' and 'createdBy' for all those models. I don't want to add them manually to all my POJOs and xml as they are huge in number.
Is it possible to create these fields dynamically through hibernate?
Sample POJO1
#BasePOJO
public class MyPOJO1 {
private String name;
private int age;
// Setter and Getter Methods
}
Hibernate XML for POJO1
<hibernate-mapping>
<class name="MyPOJO1">
<property column="name" length="50" name="name" type="string"/>
<property column="age" length="50" name="age" type="integer"/>
</class>
</hibernate-mapping>
What to be done
// TODO: Get all POJO annotated with BasePOJO
// TODO: Dynamically create the required fields
The other possible solutions i ignore
Adding those extra fields in a separate class and extending them in all my POJOs and Making all my hbm xml definitions from class to subclass extending the base class
Intention is to make the effort simple and leaving a space for more common fields of this sort to come in future. Thanks for any guidance in this regard.

How to use Hibernate composite-id without class?

I am trying to map a key in xml as follows:
<composite-id>
<key-property name="userId" column="USER_ID" />
<key-property name="passwordsBack" column="PASSWORDS_BACK" />
</composite-id>
I have seen this construction, without class="BlahPK", in the documentation, in "Hibernate in Action," and elsewhere. When I try to fetch, though, I get:
Initial SessionFactory creation failed.org.hibernate.MappingException: composite-id class must implement Serializable: MyClass
This is a very simple data class, it's not mutable, I don't need a key and certainly don't want to remodel my object and define a separate public class just to read it with Hibernate. Currently, I have it kludged to use rowid as the id, but I'd rather have the mapping cleanly reflect how the table and object are used.
Disclaimer: I searched StackOverflow and all I found was
how to handle composite key hibernate, which just says "don't do it but you can."
You can define multiple #Id properties in the entity class. like
#Entity
class User implements Serializable {
#Id
private String userId;
#Id
private String passwordsBack;
..
}
This will only be supported by Hibernate not with JPA. While you try to load this into session, you need to create an instance of User and set the id properties and the call the session.load(User.class, userinstance)
I found this hibernate documentation which will help understanding this.
http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/#entity-mapping-identifier
Section you need to look for is 2.2.3.2.2. Multiple #Id properties.
EDIT: Just realized that you need the xml description and not the annotation based solution. There might be something similar to this approach. Let me see if I can get you a reference.
Update: If you can change your class MyClass to implement Serializable, that will fix the problem and no need to have another public PK class. You need to have the equals and hashCode methods which will use you id fields.

hibernate simple inheritance - OR - xml property import/include

Final goal:
Have a few java objects sharing the same base class persisted into a database while each one having its own self-contained table with all own/inherited objects, and a simple auto-generated by the database id.
Very simple requirement. Impossible (?) with Hibernate!
What I have so far (using MySQL, Hibernate XML mapping):
map.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-access="field"
default-lazy="false">
<class name="xyz.url.hibernate.EntityBase" abstract="true">
<id name="m_id" column="id">
<generator class="identity" />
</id>
<version name="m_version" column="version" type="long" />
<union-subclass name="xyz.url.hibernate.User" table="my_entity">
<property name="name" column="name" type="string" />
</union-subclass>
</class>
</hibernate-mapping>
EntityBase.java
public abstract class EntityBase {
private final long m_id;
private final long m_version;
public EntityBase() {
this.m_id = 0;
this.m_version = 0;
}
public long get_id() {
return this.m_id;
}
public long get_version() {
return this.m_version;
}
}
User.java
public class User extends EntityBase {
public String name;
}
The above does not work unless you change the generator class to increment.
Currently this is the given error:
org.hibernate.MappingException: Cannot use identity column key generation with <union-subclass> mapping for: xyz.url.hibernate.User
Well, why does Hibernate ASSUMES I want a unique ID in a program-wide scope (I've read about some JPA requirement)... what a crap!
Anyway, I insist of having a simple table (per object) that aggregates all the object's (User in this case) properties, and deny using discriminators (again what a crap..) which just complicate the final SQL queries and hit performance.
The only solutions I see here:
Manually map all properties in a one block inside the XML.
Map all properties while "importing" some <propert> items from an external file, thus achieve inheritance (reusage of properties). Possible? How to do?!?
Explore annotations further which as far as I've seen they don't support that simple inheritance requirement.
Dump Hibernate and go with another ORM solution.
Please don't link to the docs - I gave up on that one after reading them a few times!
An example of property import (from external file) would be great.
Thanks and god bless!
First of all you need to decide whether your inheritance relationship should be mapped to the database (to allow polymorphic queries such as from EntityBase, polymorphic realtionships, etc) or not.
As far as I understand in your case it shouldn't be mapped, therefore it doesn't make sense to use inheritance mapping options such as <union-subclass> at all. Now you have the following options:
2. Hibernate doesn't have special support for reuse of XML mappings, but its documentation suggests to use XML entities in this case, see, for example, 10.1.6. Table per concrete class using implicit polymorphism.
3. Annotations certainly support this requirement in form of #MappedSuperclass annotation.
This annotation can be used to mark a class that is not mapped to the database itself, but any mapping annotations defined on its properties take effect for its mapped subclasses, so that you don't need to repeat them.
You can also use XML Entity Reference, see:
https://n1njahacks.wordpress.com/2014/09/19/hibernate-xml-mapping-fragment-re-use/
http://xml.silmaril.ie/includes.html

org.hibernate.InstantiationException: How to tell Hibernate which class to use for object instantiation

I am currently trying to replace my own database controller implementation with Hibernate and I have the following problem creating an appropriate mapping file.
(I am very new to Hibernate, so please be gentle :-) - I've read through the whole Hibernate Reference documentation but I don't have any practical experience yet).
(The whole thing should represent the relationship between email accounts and their server settings).
I have a class called MailAccount which has 2 properties (see code below):
public class MailAccount{
long id;
IncomingMailServer incomingServer;
OutgoingMailServer outgoingServer;
public MailAccount(){
super();
}
// Getter and setter omitted
}
The server class hierachy looks like this:
MailServer.java
public abstract class MailServer {
String password;
String host;
String username;
String port;
// Getter and setter omitted
}
IncomingMailServer.java
public abstract class IncomingMailServer extends MailServer {
}
OutgoingMailServer.java
public abstract class OutgoingMailServer extends MailServer {
}
Pop3Server.java
public class Pop3Server extends IncomingMailServer{
public Pop3Server(){
super();
}
}
ImapServer.java
public class ImapServer extends IncomingMailServer{
public ImapServer(){
super();
}
}
SmtpServer.java
public class SmtpServer extends OutgoingMailServer{
public SmtpServer(){
super();
}
}
The properties incomingServer and outgoingServer in MailAccount.java of course only hold instances of either Pop3Server, ImapServer (for incomingServer) or SmtpServer (for outgoingServer).
Now, I tried to create the mapping file for MailAccount:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="test.account">
<class name="MailAccount" table="MAILACCOUNTS" dynamic-update="true">
<id name="id" column="MAIL_ACCOUNT_ID">
<generator class="native" />
</id>
<component name="incomingServer" class="test.server.incoming.IncomingMailServer">
<property name="password" column="INCOMING_SERVER_PASSWORD" />
<property name="host" column="INCOMING_SERVER_PASSWORD" />
<property name="username" column="INCOMING_SERVER_PASSWORD" />
<property name="port" column="INCOMING_SERVER_PASSWORD" />
</component>
<component name="outgoingServer" class="test.server.outgoing.OutgoingMailServer">
<property name="password" column="OUTGOING_SERVER_PASSWORD" />
<property name="host" column="OUTGOING_SERVER_PASSWORD" />
<property name="username" column="OUTGOING_SERVER_PASSWORD" />
<property name="port" column="OUTGOING_SERVER_PASSWORD" />
</component>
</class>
</hibernate-mapping>
Note: Since I got a 1:1 relation between MailAccount and IncomingMailServer as well as MailAccount and OutgoingMailServer, I want everything in 1 table in order to prevent unnecessary joins.
The problem: Whenever I tell Hibernate to save an instance of MailAccount, like this:
session = getSession();
transaction = session.beginTransaction();
session.save(mailAccount);
transaction.commit();
.. I get the following exception:
org.hibernate.InstantiationException:
Cannot instantiate abstract class or
interface:
test.server.incoming.IncomingMailServer
This totally makes sense since abstract classes cannot be instantiated.
However, here comes my question: How can I tell Hibernate to create an instance of the right class (Pop3Server, SmtpServer, ImapServer) instead of the abstract ones?
Example: If the property incomingServer holds an instance of Pop3Server, then Hiberante should store that into my database and when I load the according MailAccount back, I want Hibernate to recreate an instance of Pop3Server.
The problem is occurring because a component is not a stand-alone entity, but "a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity". In JPA terms it is considered an Embeddable class. These classes are usually used to create a class object out of a number of table columns that would normally have to be stored as individual attributes in an entity (you can almost look at it as grouping).
While there are a number of benefits to this approach, there are some restrictions. One of these restrictions are that the component or embeddable cannot be an abstract class. The reason being that there isn't any way for hibernate to associate a particular concrete subclass with the value you are trying to store or read. Think of it this way: would you be able to tell what instance to create by only looking at the column data? It's usually not that straight forward, especially for the persistence engine.
In order to get the functionality you desire, you will want to look into storing MailServer data as a separate entity with its own primary key field. Doing so allows you to manage the data with subclasses using various inheritance methods such as including a DiscriminatorColumn or separate tables (depending on your configuration).
Here are some links that should help you with setting up these mappings and using entity inheritance:
One-to-One mapping example
(useful if not reusing MailServer
data.
Inheritance overview
Useful Hibernate examples (not
latest spec, but gives you good
overview)
Hope this helps.
http://www.vaannila.com/hibernate/hibernate-example/hibernate-example.html
If you were to use this approach using Hibernate (I personally prefer JPA-based Annotation configurations), you could configure MailServer as an abstract entity that would define the common column mappings between the classes and a DiscriminatorColumn (if using same table inheritance). The subclasses would be built off of this definition, adding custom attributes as needed.

Enumerations in Hibernate

It is often useful to have a field in a DAO whose value comes from a Java enumeration. A typical example is a login DAO where you usually have a field that characterises the user as "NORMAL" or "ADMIN". In Hibernate, I would use the following 2 objects to represent this relationship in a (semi-)typesafe way:
class User {
String username;
String passwd;
UserType type;
}
class UserType {
private enum Type {ADMIN, NORMAL};
private String type;
//Setters/Getters for Hibernate
public void setType(String type);
public String getType();
//Setters/Getters for user
public void setUserType(UserType.Type t);
public UserType.Type getUserType();
public static UserType fromType(UserType.Type t);
}
This works, but I find the UserType class ungly and requiring too much bureaucracy just to store a couple of values. Ideally, Hibernate should support enum fields directly and would create an extra table to store the enumeration values.
My question is: Is there any way to directly map an enumeration class in Hibernate? If not, is my pattern for representing enumerations good enough or am I missing something? What other patterns do people use?
using hibernate or JPA annotations:
class User {
#Enumerated(EnumType.STRING)
UserType type
}
UserType is just a standard java 5 enum.
I can't imagine this is just limited to just annotations but I don't actually know how to do this with hbm files. It may be very version dependant, I'm guessing but I'm pretty sure that hibernate 3.2+ is required.
edit: it is possible in a hbm, but is a little messy, have a look at this forum thread
From the Hibernate documentation: http://www.hibernate.org/272.html
You can create a new typedef for each of your enums and reference the typedefs in the property tag.
Example Mapping - inline <type> tag
<property name='suit'>
<type name="EnumUserType">
<param name="enumClassName">com.company.project.Suit</param>
</type>
</property>
Example Mapping - using <typedef>
<typedef name="suit" class='EnumUserType'>
<param name="enumClassName">com.company.project.Suit</param>
</typedef>
<class ...>
<property name='suit' type='suit'/>
</class>

Categories

Resources