2017-09-12 2 views
0

ich versuche, ein Objekt zu beharren, dass anstelle ein Integer mit dem Java-Framework winter ein Atomicinteger Variable (ich das Objekt in einem Thread sicher Szenario verwenden muß sie nach dem Speichern), aber wenn ich versuche, meine zu retten object java throws:Wie behalte ich einen AtomicInteger im Hibernate statt in Integer?

java.lang.ClassCastException: java.util.concurrent.atomic.AtomicInteger cannot be cast to java.lang.Integer 

Gibt es eine Möglichkeit, AtomicInteger zu Integer zuzuordnen? Es ist ein Beispiel für Objekt:

public class Statistics implements java.io.Serializable { 
    private AtomicInteger id; 
    private AtomicInteger totalErrors; 

    public Statistics() { 
    } 


    public AtomicInteger getTotalErrors() { 
    return this.totalErrors; 
    } 

    public void seTotalErrors(AtomicInteger totalErrors) { 
    this.totalErrors= totalErrors; 
    } 
} 

und die jeweiligen POJO xml:

<?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> 
    <class name="Statistics" table="statistics" catalog="example" optimistic-lock="version"> 
     <id name="id" type="java.lang.Integer"> 
     <column name="id" /> 
     <generator class="identity" /> 
     </id> 
     <property name="totalErrors" type="java.lang.Integer"> 
     <column name="total_errors" /> 
     </property> 
    </class> 
</hibernate-mapping> 

Und es gibt die Hibernate-Version:

<dependency> 
     <groupId>org.hibernate</groupId> 
     <artifactId>hibernate-core</artifactId> 
     <version>5.2.10.Final</version> 
    </dependency> 
    <dependency> 
     <groupId>org.hibernate</groupId> 
     <artifactId>hibernate-hikaricp</artifactId> 
     <version>5.2.10.Final</version> 
    </dependency> 
+0

In welcher Zeile sehen Sie die Ausnahme bekommen? Stellen Sie mehr Informationen zur Verfügung. Und das DAO/Repository wenn möglich. Außerdem sehe ich keine JPA- oder Hibernate-Anmerkungen in Ihrem Pojo. Geben Sie den XML-Code an, wenn Sie einen für die Zuordnung verwenden. –

Antwort

0

Schließlich ist die bessere Lösung (weil der mehr Standard Hibernate-Wandler https://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html/ch06.html), ist eine Hibernate Usertype-Klasse zu erstellen. Ich weiß nicht, was der Grund ist, weil der AttributeConverter nicht funktioniert (weil es in der Winterschlaf-Dokumentation ist).

Dies funktioniert in meinem Fall mit Hibernate 5.2. eine AtomicIntegerType erstellen, die Usertype implementiert winter:

import java.io.Serializable; 
import java.sql.PreparedStatement; 
import java.sql.ResultSet; 
import java.sql.SQLException; 
import java.util.concurrent.atomic.AtomicInteger; 
import java.util.logging.Logger; 
import org.hibernate.HibernateException; 
import org.hibernate.engine.spi.SharedSessionContractImplementor; 
import org.hibernate.usertype.UserType; 

public class AtomicIntegerType implements UserType { 

    private static final Logger logger = Logger.getLogger("AtomicInteger"); 

    /** 
    * Returns the object from the 2 level cache 
    */ 
    @Override 
    public Object assemble(final Serializable cached, final Object owner) 
      throws HibernateException { 
     //would work as the AtomicInteger.class is Serializable, 
     //and stored in cache as it is - see disassemble 
     return cached; 
    } 

    /** 
    * Used to create Snapshots of the object 
    */ 
    @Override 
    public Object deepCopy(Object value) throws HibernateException { 
     //return value; -> if AtomicInteger.class was immutable we could return the object as it is 
     final AtomicInteger recievedParam = (AtomicInteger) value; 
     final AtomicInteger atomicInteger = new AtomicInteger(recievedParam.get()); 
     return atomicInteger; 
    } 

    /** 
    * method called when Hibernate puts the data in a second level cache. The 
    * data is stored in a serializable form 
    */ 
    @Override 
    public Serializable disassemble(final Object value) throws HibernateException { 
     //For this purpose the AtomicInteger.class must implement serializable 
     return (Serializable) value; 
    } 

    /** 
    * Used while dirty checking - control passed on to the 
    * {@link AtomicInteger} 
    */ 
    @Override 
    public boolean equals(final Object o1, final Object o2) throws HibernateException { 
     boolean isEqual = false; 
     if (o1 == o2) { 
      isEqual = true; 
     } 
     if (null == o1 || null == o2) { 
      isEqual = false; 
     } else { 
      isEqual = o1.equals(o2); 
     } 
     return isEqual; 
     //for this to work correctly the equals() 
     //method must be implemented correctly by AtomicInteger class 
    } 

    @Override 
    public int hashCode(final Object value) throws HibernateException { 
     return value.hashCode(); 
     //for this to work correctly the hashCode() 
     //method must be implemented correctly by AtomicInteger class 

    } 

    /** 
    * Helps hibernate apply certain optimizations for immutable objects 
    */ 
    @Override 
    public boolean isMutable() { 
     return true; //The audit fields can be modified 
    } 

    /** 
    * This method retrieves the property value from the JDBC resultSet 
    */ 
    @Override 
    public Object nullSafeGet(ResultSet resultSet, String[] names, SharedSessionContractImplementor ssci, Object owner) throws HibernateException, SQLException { 
     //owner here is class from where the call to retrieve data was made. 
     //In this case the Test class 
     AtomicInteger atomicInteger = null; 
     if (!resultSet.wasNull()) { 
      atomicInteger = new AtomicInteger(resultSet.getInt(names[0]));    
     } 
     return atomicInteger; 
    } 

    /** 
    * The method writes the property value to the JDBC prepared Statement 
    * 
    */ 
    @Override 
    public void nullSafeSet(final PreparedStatement statement, 
      final Object value, final int index, SharedSessionContractImplementor ssci) throws HibernateException, 
      SQLException { 
     if (null == value) { 
      statement.setNull(index, java.sql.Types.INTEGER); 
     } else { 
      AtomicInteger atomicInteger = (AtomicInteger) value; 
      if (null != atomicInteger) { 
       statement.setInt(index , atomicInteger.get()); 
      } else { 
       statement.setNull(index, java.sql.Types.INTEGER); 
      } 

     } 
    } 

    /** 
    * Method used by Hibernate to handle merging of detached object. 
    */ 
    @Override 
    public Object replace(final Object original, final Object target, 
      final Object owner) 
      throws HibernateException { 
     //return original; // if immutable use this 
     //For mutable types at bare minimum return a deep copy of first argument 
     return this.deepCopy(original); 

    } 

    /** 
    * Method tells Hibernate which Java class is mapped to this Hibernate Type 
    */ 
    @SuppressWarnings("rawtypes") 
    @Override 
    public Class returnedClass() { 
     return AtomicInteger.class; 
    } 

    /** 
    * Method tells Hibernate what SQL columns to use for DDL schema generation. 
    * using the Hibernate Types leaves Hibernate free to choose actual SQl 
    * types based on database dialect. (Alternatively SQL types can also be 
    * used directly) 
    */ 
    @Override 
    public int[] sqlTypes() { 
     //createdBy, createdDate,modifiedBy,modifiedDate 
     return new int[]{java.sql.Types.INTEGER}; 
    } 

} 

Und in der Hibernate Mapping-Integer-Datei Änderung AtomicIntegerType wie folgt:

<?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"> 
<!-- Generated 12-sep-2017 13:14:50 by Hibernate Tools 4.3.1 --> 
<hibernate-mapping> 
    <class name="classs.location.Statistics" table="statistics" catalog="CATALOG" optimistic-lock="version"> 
     <id name="id" type="java.lang.Integer"> 
     <column name="id" /> 
     <generator class="identity" /> 
     </id> 
     <property name="totalErrors" type="class.location.AtomicIntegerType"> 
     <column name="total_errors" /> 
     </property> 
    </class> 
</hibernate-mapping> 
+0

Sicher, UserType funktioniert auch, aber angesichts aller Implementierungsdetails, die Sie bereitstellen müssen, ist es viel fehleranfälliger als einen einfachen Konverter zu schreiben. Aber ich bin froh, dass Sie eine funktionierende Lösung gefunden haben. –

+0

Sicher! und einfacher zu implementieren, aber aus irgendeinem Grund funktioniert es nicht. Vielen Dank für deine Hilfe! – Martin

2

Eine Möglichkeit, es zu tun ist, ein schreiben JPA 2.1 AttributeConverter, das von einem Integer in einen AtomicInteger konvertiert, wie unter

Normalerweise können Sie dann die JPA @Convert Anmerkung auf Ihrer @Entity Klassenfelder wie folgt verwenden:

@Convert(converter = AtomicIntConverter.class) 
private AtomicInteger totalErrors; 

Sie können in der Hibernate 5.2 documentation here.

mehr darüber lesen Aber wie Sie eine Hibernate Mapping-Datei verwenden, Stellen Sie sicher, dass Sie den FQN der Konverterklasse als Typ des Felds festlegen, anstatt die Annotation @Converter zu verwenden.

<property name="totalErrors" type="fully.qualified.name.of.AtomicIntConverter"> 
    <column name="total_errors" /> 
</property> 
+0

Danke! Ich versuche es, aber es funktioniert nicht in Hibernate 5.2.10.Final – Martin

+0

Das ist seltsam, wie es in der Hibernate5.2 Dokumentation vorhanden ist –

+0

@martin Ich bin mir ziemlich sicher, dass das Problem liegt mit Ihrem Hibernate Mapping XML-Datei. Versuchen Sie, den 'type =" java.lang.Integer "' auf 'type =" path.to.AtomicIntConverter "' –

Verwandte Themen