Enumerations in Hibernate - java

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>

Related

Map complex value objects in Hibernate

I've already asked this question on the Hibernate's forum, but I thought I'd ask it here too.
I'm trying to map the following model while preserving the value semantics of the TranslatedText and Translation value objects:
Both values as dependent objects
Ideally I'd map TranslatedText as a <component> within Question and Translation as a <bag> of <composite-element> within TranslatedText.
It would have been simple to map if Question was only referencing one TranslatedText, but since it references two I need some kind of discriminator based on the name of the property holding the value (title or description) in order to map the Translation with a foreing key composed of (question_id,property_name,language_code).
One problem with that is that the propertyName isin't part of the model and shouldn't, but I haven't found a way to force Hibernate to insert a value that doesn't come from the model.
Therefore, I tried to change the model and introduce specialized Title and Description classes so that I'd have a type in there that I could use as a discriminator.
At the end that did not really help much:
<component name="title" class="TranslatedText">
<bag name="translations" table="Translation">
<key>
<!-- PROBLEM: Could not find a way to create a custom join expression on question.id and question.title.type in here. -->
</key>
<composite-element class="Translation">
<!-- PROBLEM: Could not found a way to make Hibernate insert title.type from here, without having this value on the Translation object. -->
<property name="languageCode" type="string" column="language_code"/>
<property name="text" type="string"/>
</composite-element>
</bag>
</component>
TranslatedText with <many-to-one>
I managed to get something close to what I need by mapping TranslatedText as an entity within Question using a <many-to-one> and then map Translation as a collection of values within TranslatedText, but the main problem with that approach is that there is no easy way to get rid of the orphaned TranslatedText and Translation. I'd either have to do this with a DB trigger or a scheduled process.
Conclusion
At this point I'm under the impression that Hibernate is not flexible enough to map the initial model with the proper semantics, but hopefully I'm wrong and there is a way to do it.
I have not found a way to map them as values. However the next solution works and it might be helpful for you. I removed TranslatedText and linked Question directly with collection of Translation.
#Entity
public class Question {
#Id
private String id;
#JoinTable
#OrderColumn
#OneToMany(fetch = EAGER, cascade = ALL)
private List<Translation> titleTranslations;
#JoinTable
#OrderColumn
#OneToMany(fetch = EAGER, cascade = ALL)
private List<Translation> descriptionTranslations;
}
The drawback here is that Translation has to be Entity class.
#Entity
public class Translation {
#Id
private String id;
private String languageCode;
private String text;
}

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

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

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.

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.

Categories

Resources