Array mit UserType in Hibernate und PostgreSQL -> MappingException

Ich versuche, eine Klasse zu schreiben, die UserType implementiert, um mit Arrays in Hibernate / JPA umzugehen. Ich habe die folgenden Beiträge verwendetAbbildung eines Postgres-Arrays mit Ruhezustand undRuhezustand / JPA / HSQL: Erstellen einer Dialektzuordnung für den Benutzertyp ARRAY um eine Lösung zu entwickeln, aber ich kann sie nicht zum Laufen bringen. Ich habe ein neues Spring Roo-Projekt erstellt, um es zu testen. Hier sind die verschiedenen Dateien (alle Java-Klassen befinden sich im Pakettest):

persistence.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <properties>
    <!--  <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/> -->
    <property name="hibernate.dialect" value="test.PostgreSQLDialectArray"/>
    <!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database -->
    <property name="hibernate.hbm2ddl.auto" value="create"/>
    <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
    <property name="hibernate.connection.charSet" value="UTF-8"/>
    <!-- Uncomment the following two properties for JBoss only -->
    <!-- property name="hibernate.validator.apply_to_ddl" value="false" /-->
    <!-- property name="hibernate.validator.autoregister_listeners" value="false" /-->
    </properties>
  </persistence-unit>
</persistence>

TestArray.java

package test;

import java.math.BigInteger;
import java.security.SecureRandom;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.serializable.RooSerializable;
import org.springframework.roo.addon.tostring.RooToString;

@RooJavaBean
@RooToString
@RooSerializable
public class TestArray {


     private static final long serialVersionUID = 1L;
     private SecureRandom random = new SecureRandom();


     public String nextSessionId()
     {
         return new BigInteger(130, random).toString(32);
     }

     public static void main(String[] args) {
         ApplicationContext context;
 context = new ClassPathXmlApplicationContext("classpath:META-INF/spring/applicationContext.xml");
         int[] array = new int[1428];
         TestArray test = new TestArray();
         Blabla blabla = new Blabla();
         int nb = 1428;

         for(int i = 0 ; i < nb ; i++)
         array[i] = test.random.nextInt();

          //         blabla.setTest(array);
          //         blabla.persist();
          //        System.out.println(Arrays.toString(blabla.getTest()));

         System.out.println(java.sql.Types.ARRAY);
         System.out.println("Done");
     }
}

Blabla.java

package test;

import org.hibernate.annotations.Type;
import org.springframework.roo.addon.entity.RooEntity;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.tostring.RooToString;

@RooJavaBean
@RooToString
@RooEntity
public class Blabla {

    @Type(type = "test.IntArrayUserType")
    private int[] array;
}

PostgreSQLDialectArray

package test;

import java.sql.Types;


public class PostgreSQLDialectArray extends org.hibernate.dialect.PostgreSQLDialect{

    public PostgreSQLDialectArray() { 
        super(); 
        registerHibernateType(Types.ARRAY, "array"); 
    }
 }

IntArrayUserType.java (im Grunde das gleiche wie inAbbildung eines Postgres-Arrays mit Ruhezustand)

package test;
import java.io.Serializable;
import java.sql.Array;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;



public class IntArrayUserType implements UserType {

    protected static final int  SQLTYPE = java.sql.Types.ARRAY;

    private int[] toPrimitive(Integer[] array){
        int[] a = new int[array.length];
        for(int i = 0 ; i < array.length ; i++)
            a[i] = array[i];
        return a;
    }

    private Integer[] toObject(int[] array){
        Integer[] a = new Integer[array.length];
        for(int i = 0 ; i < array.length ; i++)
            a[i] = array[i];
        return a;
    }

    @Override
    public Object nullSafeGet(final ResultSet rs, final String[] names, final Object owner) throws HibernateException, SQLException {
        Array array = rs.getArray(names[0]);
        Integer[] javaArray = (Integer[]) array.getArray();
        return toPrimitive(javaArray);
    }

    @Override
    public void nullSafeSet(final PreparedStatement statement, final Object object, final int i) throws HibernateException, SQLException {
        System.out.println("test null safe set...");
        Connection connection = statement.getConnection();

        int[] castObject = (int[]) object;
        Integer[] integers = toObject(castObject);
        Array array = connection.createArrayOf("integer", integers);

        statement.setArray(i, array);
        System.out.println("test null safe set...");
    }

    @Override
    public Object assemble(final Serializable cached, final Object owner) throws HibernateException {
        return cached;
    }

    @Override
    public Object deepCopy(final Object o) throws HibernateException {
        return o == null ? null : ((int[]) o).clone();
    }

    @Override
    public Serializable disassemble(final Object o) throws HibernateException {
        return (Serializable) o;
    }

    @Override
    public boolean equals(final Object x, final Object y) throws HibernateException {
        return x == null ? y == null : x.equals(y);
    }

    @Override
    public int hashCode(final Object o) throws HibernateException {
        return o == null ? 0 : o.hashCode();
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Object replace(final Object original, final Object target, final Object owner) throws HibernateException {
        return original;
    }

    @Override
    public Class<int[]> returnedClass() {
        return int[].class;
    }

    @Override
    public int[] sqlTypes() {
        return new int[] { SQLTYPE };
    }
}

Und jetzt der Stacktrace:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class path resource [META-INF/spring/applicationContext.xml]: Cannot resolve reference to bean 'entityManagerFactory' while setting bean property 'entityManagerFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [META-INF/spring/applicationContext.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: persistenceUnit] Unable to build EntityManagerFactory
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1325)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1086)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at test.TestArray.main(TestArray.java:29)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [META-INF/spring/applicationContext.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: persistenceUnit] Unable to build EntityManagerFactory
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1420)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:322)
... 15 more
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: persistenceUnit] Unable to build EntityManagerFactory
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:915)
at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:74)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:225)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:308)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
... 22 more
Caused by: org.hibernate.MappingException: No Dialect mapping for JDBC type: 2003
at org.hibernate.dialect.TypeNames.get(TypeNames.java:77)
at org.hibernate.dialect.TypeNames.get(TypeNames.java:100)
at org.hibernate.dialect.Dialect.getTypeName(Dialect.java:296)
at org.hibernate.mapping.Column.getSqlType(Column.java:208)
at org.hibernate.mapping.Table.sqlCreateString(Table.java:418)
at org.hibernate.cfg.Configuration.generateSchemaCreationScript(Configuration.java:1099)
at org.hibernate.tool.hbm2ddl.SchemaExport.<init>(SchemaExport.java:106)
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:372)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1872)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:906)
... 27 more

Also denke ich, dass der von mir erstellte Dialekt überhaupt nicht verwendet wird oder falsch ist, aber ich weiß nicht warum. Ich denke, dass die @Type-Annotation das Mapping durchführen sollte, aber ich habe einige Tags gesehen, aber ich weiß nicht, ob sie in diesem Beispiel benötigt werden und wenn ja, wo hatte ich sie? Es ist zwei Tage her, dass ich mit diesem Problem festgefahren bin und ich werde verzweifelt. Könnten Sie mir helfen, dieses Programm zu debuggen? Bitte. Vielen Dank im Voraus.

0 bearbeiten:

Die Datei persistence.xml scheint den richtigen Dialekt zu finden, aber die Funktion getTypeName (2003) löst die obigen Fehler aus, nachdem registerHibernateType (Types.ARRAY, "array") ausgeführt wurde. Übrigens verwende ich Hibernate 3.6.4.Final und postgresql 8.4-702.jdbc3.

Bearbeiten 1:

Ich habe die folgende Zeile zum PostgreSQLDialectArray-Konstruktor hinzugefügt:

registerColumnType(Types.ARRAY, "integer[$l]" ); 

das scheint das Problem teilweise zu lösen. Jetzt erhalte ich jedoch einen weiteren Fehler:

2013-01-09 11:14:30,281 [main] ERROR org.hibernate.tool.hbm2ddl.SchemaExport - Unsuccessful: create table blabla (id int8 not null, array int[255], name varchar(255), test int4 not null, version int4, primary key (id))
2013-01-09 11:14:30,282 [main] ERROR org.hibernate.tool.hbm2ddl.SchemaExport - ERREUR: erreur de syntaxe sur ou près de « array »
  Position: 40

Anscheinend weiß der Ruhezustand immer noch nicht, wie man eine Tabelle mit einem Array erstellt ...

Bearbeiten 2:

Es scheint, dass postgresql die Tatsache nicht gefallen hat, dass meine Spalte "Array" genannt wurde. Ich ändere das und es hat funktioniert. Die Tabelle wird im Ruhezustand mit einem ganzzahligen Array erstellt.

ABER ich kann wegen eines Problems in der UserType-Implementierung kein Array im Ruhezustand speichern. Anscheinend schlägt die Erstellung des Arrays mit createArrayOf fehl. Ich lese einige Threads zu diesem Thema, in denen darauf hingewiesen wird, auf die zugrunde liegende Verbindung anstatt auf den Wrapper zuzugreifen. Ich denke, ich werde einen neuen Thread eröffnen, der auf diesen verweist, da dieses Problem ganz anders ist.

Der Stacktrace:

Exception in thread "main" java.lang.AbstractMethodError: org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.createArrayOf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/sql/Array;
at test.IntArrayUserType.nullSafeSet(IntArrayUserType.java:59)
at org.hibernate.type.CustomType.nullSafeSet(CustomType.java:140)
at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2184)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2430)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2874)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:76)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:467)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$afterReturning$org_springframework_transaction_aspectj_AbstractTransactionAspectRuhezustand / JPA / HSQL: Erstellen einer Dialektzuordnung für den Benutzertyp ARRAY2a73e96c(AbstractTransactionAspect.aj:78)
at test.Blabla_Roo_Entity.ajc$interMethod$test_Blabla_Roo_Entity$test_Blabla$persist(Blabla_Roo_Entity.aj:56)
at test.Blabla.persist(Blabla.java:1)
at test.Blabla_Roo_Entity.ajc$interMethodDispatch1$test_Blabla_Roo_Entity$test_Blabla$persist(Blabla_Roo_Entity.aj)
at test.TestArray.main(TestArray.java:39)

Edit 3:

Nach den folgenden Änderungen funktioniert der UserType für Integer-Arrays:

Fügen Sie diese Zeile in applicationContext.xml hinzu in:

<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
....
<property name="accessToUnderlyingConnectionAllowed" value="true" />
</bean>

Ändern Sie das NullSafeSet von IntArrayUserType

    @Override
    public void nullSafeSet(final PreparedStatement statement, final Object object, final int i) throws HibernateException, SQLException {
        Connection connection = statement.getConnection();
        int[] castObject = (int[]) object;
        Integer[] integers = toObject(castObject);
        Connection conn = ((DelegatingConnection) connection).getInnermostDelegate();
        Array array = conn.createArrayOf("integer", integers);
        statement.setArray(i, array);
    }

ABER es gibt immer noch ein Problem, wenn alle Einträge aus der Tabelle blabla abgerufen werden: Die Funktion findAllBlablas funktioniert nicht richtig und gibt nur den ersten Eintrag zurück ...

Bearbeiten 4:

Tatsächlich hat es hervorragend funktioniert, aber die Eclipse-Konsole konnte nicht alle Daten drucken. Das ist alles!

Antworten auf die Frage(2)

Ihre Antwort auf die Frage