Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

separating JPA entities from Hibernate-specific tweaks

I have the following "root" entity (hibernate-specific parts commented out):

@Entity
//@GenericGenerator(name="system-uuid",strategy="org.hibernate.id.UUIDGenerator")
public class Node extends PersistentEntity {
    private UUID id;
    private String name;
    private String displayName;

    @Id
    @GeneratedValue
    //@GeneratedValue(generator="system-uuid") //instead of above line
    //@Type(type = "pg-uuid")
    public UUID getId() { return id; }

    public String getName() { return name; }

    public String getDisplayName() { return displayName; }

    //stuff omitted
}

this is part of a persistence context deployed on JBoss AS 6 (hibernate 3.6) using PostgreSQL 9 for the database (using the latest JDBC4 driver). PostgreSQL has its own uuid column type, which requires some hibernate-specific mappings to use properly (commented out in the above code) - otherwise hibernate will try to map the UUID field to BINARY, then the PostgreSQL dialect does not support BINARY (apparently because postgre has 2 ways of storing binary and hibernate devs dont like it) and the whole thing explodes.

uncommenting the lines above produces working code, but it forces me to have a compile-time dependency on hibernate - which i'd rather avoid.

attempting to add an hbm.xml file into the mix and referencing it from the persistence.xml does not merge data from the file and annotations, but simply ignores the annotations:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="package">
    <class name="Node">
        <id name="id" type="pg-uuid">
            <generator class="org.hibernate.id.UUIDGenerator"/>
        </id>
    </class>
</hibernate-mapping>

i can "fluff" this file up by adding the extra 2 properties, but even if i do that (at which point the Node class works), adding any extra entities, like:

@Entity
public class Host extends Node {
    //fields, getters, fluff
}

i get the following exception:

org.hibernate.DuplicateMappingException: Duplicate class/entity mapping Node

since hibernate "finds" Node twice. is there any elegant way around this? ideally, Node is the only class for which i'll need hibernate-specific properties, and it will be the root of a large hierarchy of classes. i'd like to avoid either compile-time dependencies on hibernate or mapping everything completely in hbm.xml. for completeness' sake, here's the persistence.xml file im using:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
    <persistence-unit name="myPU" transaction-type="JTA">
        <jta-data-source>java:/my-postgresql-DS</jta-data-source>
        <mapping-file>META-INF/hbm.xml</mapping-file>
        <!-- shouldnt need to list classes here since this is deployed -->
        <!-- in the same jar as the classes and scanning should work   -->
        <validation-mode>AUTO</validation-mode>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
        </properties>
    </persistence-unit>
</persistence>
like image 946
radai Avatar asked Jan 30 '11 09:01

radai


1 Answers

I have a couple of suggestions that may simplify or route around the problem, though I'm not answering your specific question about hbm.xml.

1) You can manually generate your IDs. Leave off the @GeneratedValue and I believe you can just use Java's UUID.randomUUID() to generate a RFC 4122 compliant UUID like Hibernate's 'uuid2' generator. I haven't used that specific generator in Hibernate, but if all you want is a valid UUID, it seems like manually generating it might help you avoid some of the configuration dance.

2) Personally I just store UUIDs (albeit for non-id columns) in PostgreSQL in varchar columns. I find when it comes time for database sleuthing, I'm cutting and pasting UUIDs from log files, and it makes it easier to query. When the UUID was stored as BINARY, it was impossible, which is why we changed them to varchar. We considered UUID columns but varchar makes so many things simpler and improves interoperability. It's trivial to encapsulate the String-to-UUID conversion in your Java class.

Of course you may have to use the UUID column type for legacy reasons, or you might prefer it for performance reasons. At least one person has done a performance comparison of the two approaches.

like image 200
David Noha Avatar answered Nov 15 '22 14:11

David Noha