Postgresql UUID compatible con Hibernate?

No puedo hacer que Hibernate trabaje con java.utiliránID para PostgreSQL.

Aquí está el mapeo usando las anotaciones javax.persistence. *:

private UUID itemUuid; @Column(name="item_uuid",columnDefinition="uuid NOT NULL") public UUID getItemUuid() { return itemUuid; } public void setItemUuid(UUID itemUuid) { this.itemUuid = itemUuid; } 

Al persistir un objeto transitorio obtengo una SQLGrammarException:

 column "item_uuid" is of type uuid but expression is of type bytea at character 149 

La versión de PostgreSQL es 8.4.4
Controlador JDBC – 8.4.4-702 (también intenté 9.0 – lo mismo)
La versión de Hibernate es 3.6, propiedades principales de configuración:

 org.hibernate.dialect.PostgreSQLDialect org.postgresql.Driver jdbc:postgresql://192.168.1.1/db_test 

Esto se puede resolver agregando la siguiente anotación al UUID:

 import org.hibernate.annotations.Type; ... @Type(type="pg-uuid") private java.util.UUID itemUuid; 

En cuanto a por qué Hibernate no solo hace de esto la configuración predeterminada, no podría decirte …

ACTUALIZACIÓN: Todavía parece haber problemas con el método createNativeQuery para abrir objetos que tienen campos UUID. Afortunadamente, el método createQuery hasta ahora me ha funcionado bien.

Intenta persistir el objeto de tipo UUID, que no es una entidad con hibernación anotada. Entonces, el hibernate quiere serializarlo en una matriz de bytes (tipo blob). Es por eso que recibes este mensaje ‘expresión de tipo bytea’.

Puede almacenar UUID como blobs en la base de datos (no elegante), o proporcionar su serializador personalizado (mucho trabajo) o convertir manualmente ese objeto. La clase UUID tiene métodos fromString y toString, por lo que lo almacenaría como String.

Como mencionaron otros, la solución a este problema es agregar una @Type(type = "pg-uuid") . Sin embargo, este tipo no es compatible con los tipos UUID de otros proveedores, por lo que esto vincula sus clases Hibernate a Postgres. Para solucionar esto, es posible insertar esta anotación en tiempo de ejecución. El siguiente funciona para Hibernate 4.3.7.

En primer lugar, debe insertar un proveedor de metadatos personalizado para insertar las anotaciones. Haga esto como el primer paso después de crear una instancia de la clase de Configuration :

 // Perform some test to verify that the current database is Postgres. if (connectionString.startsWith("jdbc:postgresql:")) { // Replace the metadata provider with our custom metadata provider. MetadataProviderInjector reflectionManager = MetadataProviderInjector)cfg.getReflectionManager(); reflectionManager.setMetadataProvider(new UUIDTypeInsertingMetadataProvider(reflectionManager.getMetadataProvider())); } 

Este proveedor de metadatos personalizado busca campos y métodos de tipo UUID . Si encuentra uno, inserta una instancia de la anotación org.hibernate.annotations.Type que indica que el tipo debe ser "pg-uuid" :

 package nl.gmt.data; import org.hibernate.annotations.Parameter; import org.hibernate.annotations.Type; import org.hibernate.annotations.common.reflection.AnnotationReader; import org.hibernate.annotations.common.reflection.MetadataProvider; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.UUID; class UUIDTypeInsertingMetadataProvider implements MetadataProvider { private final Map cache = new HashMap<>(); private final MetadataProvider delegate; public UUIDTypeInsertingMetadataProvider(MetadataProvider delegate) { this.delegate = delegate; } @Override public Map getDefaults() { return delegate.getDefaults(); } @Override public AnnotationReader getAnnotationReader(AnnotatedElement annotatedElement) { // This method is called a lot of times on the same element, so annotation // readers are cached. We only cache our readers because the provider // we delegate to also caches them. AnnotationReader reader = cache.get(annotatedElement); if (reader != null) { return reader; } reader = delegate.getAnnotationReader(annotatedElement); // If this element is a method that returns a UUID, or a field of type UUID, // wrap the returned reader in a new reader that inserts the "pg-uuid" Type // annotation. boolean isUuid = false; if (annotatedElement instanceof Method) { isUuid = ((Method)annotatedElement).getReturnType() == UUID.class; } else if (annotatedElement instanceof Field) { isUuid = ((Field)annotatedElement).getType() == UUID.class; } if (isUuid) { reader = new UUIDTypeInserter(reader); cache.put(annotatedElement, reader); } return reader; } private static class UUIDTypeInserter implements AnnotationReader { private static final Type INSTANCE = new Type() { @Override public Class annotationType() { return Type.class; } @Override public String type() { return "pg-uuid"; } @Override public Parameter[] parameters() { return new Parameter[0]; } }; private final AnnotationReader delegate; public UUIDTypeInserter(AnnotationReader delegate) { this.delegate = delegate; } @Override @SuppressWarnings("unchecked") public  T getAnnotation(Class annotationType) { if (annotationType == Type.class) { return (T)INSTANCE; } return delegate.getAnnotation(annotationType); } @Override public  boolean isAnnotationPresent(Class annotationType) { return annotationType == Type.class || delegate.isAnnotationPresent(annotationType); } @Override public Annotation[] getAnnotations() { Annotation[] annotations = delegate.getAnnotations(); Annotation[] result = Arrays.copyOf(annotations, annotations.length + 1); result[result.length - 1] = INSTANCE; return result; } } } 

Solución para alguien que no usa JPA.

Antes de:

    

Después: