Question

I am using Hibernate + JPA as my ORM solution.

I am using HSQL for unit testing and PostgreSQL as the real database.

I want to be able to use Postgres's native UUID type with Hibernate, and use the UUID in its String representation with HSQL for unit testing (since HSQL does not have a UUID type).

I am using a persistence XML with different configurations for Postgres and HSQL Unit Testing.

Here is how I have Hibernate "see" my custom UserType:

@Id
@Column(name="UUID", length=36)
@org.hibernate.annotations.Type(type="com.xxx.UUIDStringType")
public UUID getUUID() {
    return uuid;
}


public void setUUID(UUID uuid) {
    this.uuid = uuid;
}

and that works great. But what I need is the ability to swap out the "com.xxx.UUIDStringType" part of the annotation in XML or from a properties file that can be changed without re-compiling.

Any ideas?

Was it helpful?

Solution

This question is really old and has been answered for a long time, but I recently found myself in this same situation and found a good solution. For starters, I discovered that Hibernate has three different built-in UUID type implementations:

  1. binary-uuid : stores the UUID as binary
  2. uuid-char : stores the UUID as a character sequence
  3. pg-uuid : uses the native Postgres UUID type

These types are registered by default and can be specified for a given field with a @Type annotation, e.g.

@Column
@Type(type = "pg-uuid")
private UUID myUuidField;

There's also a mechanism for overriding default types in the Dialect. So if the final deployment is to talk to a Postgres database, but the unit tests use HSQL, you can override the pg-uuid type to read/write character data by writing a custom dialect like so:

public class CustomHSQLDialect extends HSQLDialect {

    public CustomHSQLDialect() {
        super();

        // overrides the default implementation of "pg-uuid" to replace it
        // with varchar-based storage.
        addTypeOverride(new UUIDCharType() {
            @Override
            public String getName() {
                return "pg-uuid";
            }
        });
    }
}

Now just plug in the custom dialect, and the the pg-uuid type is available in both environments.

OTHER TIPS

Hy, for those who are seeking for a solution in Hibernate 4 (because the Dialect#addTypeOverride method is no more available), I've found one, underlying on this Steve Ebersole's comment

You have to build a custom user type like this one :

public class UUIDStringCustomType extends AbstractSingleColumnStandardBasicType {

    public UUIDStringCustomType() {
        super(VarcharTypeDescriptor.INSTANCE, UUIDTypeDescriptor.INSTANCE);
    }

    @Override
    public String getName() {
        return "pg-uuid";
    }

}

And to bind it to the HSQLDB dialect, you must build a custom dialect that override the Dialect#contributeTypes method like this :

public class CustomHsqlDialect extends HSQLDialect {


    @Override
    public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
        super.contributeTypes(typeContributions,serviceRegistry);
        typeContributions.contributeType(new UUIDStringCustomType());
    }

}

Then you can use the @Type(type="pg-uuid") with the two databases.

Hope it will help someone...

To avoid problems between the UUID types without specifying the @Type annotation (which basically means you have to adjust all annotations when you want to change from postgres to mysql or the other way around...) I'm using a package-info.java with the hibernates @TypeDef annotation on that package.

Here's an example setup of your application:
Assuming module/src/main/java/app.package.domain contains your entities. And you'r tests are stored in module/src/test/java/app.package.

Simply create two package-info.java in your domain packages.

Make sure the package-info files are always in the same package (for testing and production). See the following example below:

src/main/java
  app
    package
      domain
        package-info.java 

src/test/java
  app
    package
      domain
        package-info.java 

The content of you're production package-info.java should look like this (Postgres):

@TypeDef(
  name = "pg-uuid",
  defaultForType = UUID.class,
  typeClass = PostgresUUIDType.class
)
package app.package.domain;

import org.hibernate.annotations.TypeDef;
import org.hibernate.type.PostgresUUIDType;

import java.util.UUID;

And this is how you'r testing "configuration" should look like (H2):

@TypeDef(
  name = "uuid-char",
  defaultForType = UUID.class,
  typeClass = UUIDCharType.class
)
package app.package.domain;

import org.hibernate.annotations.TypeDef;
import org.hibernate.type.UUIDCharType;

import java.util.UUID;

Hope it helps

Perhaps you can build some smarts in your user type to do the right thing depending on the database capabilities. Hibernate itself takes a similar approach with its "native" ID generator, which behaves differently depending on the type of database you are using. An approach like this eliminates the need to switch the mapping at runtime.

For example, you could create one strategy class for each database. Then in your user type class, detect what database you're connected to when you're called for the first time, instantiate the proper strategy for that database, and then delegate all calls to the strategy object.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top