2017-09-12 19 views
0

我試着堅持認爲必須使用休眠 Java框架(我需要使用對象的線程安全的方案之後保存)的的AtomicInteger變量,而不是一個整數但是當我嘗試保存我的對象對象java拋出:如何在Hibernate而不是Integer中保留AtomicInteger?

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

有沒有辦法將AtomicInteger映射到整數?有對象的示例:

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; 
    } 
} 

和相應的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> 

而且有Hibernate的版本:

<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

在哪一行,你得到的異常?提供更多信息。如果可能,還有DAO/Repository。此外,我沒有在您的Pojo中看到任何JPA或Hibernate註釋。如果您使用映射也提供xml。 –

回答

0

最後更好的解決方案(因爲是比較標準的休眠轉換器https://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html/ch06.html),是創建一個Hibernate的用戶類型類。我不知道是什麼原因,因爲AttributeConverter不起作用(因爲它在hibernate文檔中)。

這在我的情況下工作與休眠5.2。 創建實現休眠用戶類型的AtomicIntegerType:

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}; 
    } 

} 

而且在Hibernate映射文件更改整型AtomicIntegerType如下:

<?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

當然,UserType也可以工作,但在給出所有必須提供的實現細節之後,與編寫簡單的Converter相比,它更容易出錯。但很高興你找到了一個工作解決方案 –

+0

當然!更容易實現它,但由於任何原因它不起作用。非常感謝您的幫助! – Martin

2

一種方式做到這一點是寫JPA 2.1 AttributeConverter,從Integer轉換爲AtomicInteger,如下所示

@Converter 
public class AtomicIntConverter implements AttributeConverter<AtomicInteger, Integer> { 


@Override 
public Integer convertToDatabaseColumn(AtomicInteger attribute) { 
    return attribute.get(); 
} 

@Override 
public AtomicInteger convertToEntityAttribute(Integer dbData) { 
    return new AtomicInteger(dbData); 
} 

} 

通常情況下,你可以再使用JPA @Convert註釋您@Entity類字段是這樣的:

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

你可以閱讀更多關於它的Hibernate 5.2 documentation here.

但是當你使用的是Hibernate映射文件,請確保將Converter類的FQN設置爲字段的類型,而不是使用@Converter註釋。

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

謝謝!我嘗試它,但它不工作在休眠5.2.10.Final – Martin

+0

這很奇怪,因爲它存在於Hibernate5.2文檔 –

+0

@martin我很確定問題在於你的hibernate映射xml文件。嘗試將'type =「java.lang.Integer」'調整爲'type =「path.to.AtomicIntConverter」' –

相關問題