2016-11-15 2 views
0

Je suis en veille prolongée 4.3.11.Final sur Java 7 et JPAattribut d'entité Hibernate/JPA avec un UserType pas correctement chargé

J'ai créé un UserType au maréchal/unmarshal un objet ENUM java à la base de données le stocker comme un SMALLINT.

L'énumération est un attribut d'un objet Adresse et représente la zone/localité générale de l'adresse.

Mon problème est le suivant:

Quand je charge l'adresse directement .: par exemple

Address anAddress = session.get(Address.class, 123L); 

il charge bien et je peux accéder à la AreaEnum par exemple

assert anAddress.getArea() != null; // ALL GOOD 

Cependant, quand j'accéder à une adresse par le biais d'une relation globale d'une autre entité du AreaEnum est pas mobilisée et renvoie un null, par exemple,

Person aPerson = session.get(Person.class, 5L); 

assert aPerson.getAddress().getArea() != null; // FAILS HERE 

D'autres attributs standard (qui ont des annotations de définitions de colonnes simples) sont renseignés correctement.

Mon annotation pour l'attribut Zone est comme ceci:

public class Address { 
... 
    @Type(type = "mls.dao.util.HibernateAreaEnumType") 
    @Column(name = "are_id", nullable = false, updatable = true, columnDefinition = "SMALLINT") 
    public AreaEnum getArea() { 
     return this.area; 
    } 

    @Override 
    public void setArea(AreaEnum _area) { 
     this.area = _area; 
    } 
... 
} 

Voici la classe HibernateAreaEnumType UserType:

public class HibernateAreaEnumType implements UserType { 

    private final Method parseMethod; 

    private final Class clazz; 

    public HibernateAreaEnumType() { 

     clazz = AreaEnum.class; 
     try { 
     // this is a static method 
     this.parseMethod = clazz.getMethod("parseEnum", Long.class); 
     } catch (Exception e) { 
     throw new IllegalStateException("issue with trying get the parse method of this enum class: " + clazz.getSimpleName(), e); 
     } 
    } 

    @Override 
    public Object nullSafeGet(ResultSet _rs, String[] _names, SessionImplementor _sessionImplementor, Object _owner) throws HibernateException, SQLException { 

     Object result = null; 

     if (!_rs.wasNull()) { 
     Long enumId = (long) _rs.getInt(_names[0]); 
     try { 
      result = this.parseMethod.invoke(null, enumId); 
     } catch (Exception e) { 
      throw new HibernateException("issue trying to method to parse value to make enum: " + enumId, e); 
     } 
     } 

     return result; 
    } 

    @Override 
    public void nullSafeSet(PreparedStatement _ps, Object _value, int _index, SessionImplementor _sessionImplementor) throws HibernateException, SQLException { 
     try { 
     if (null == _value) { 
      _ps.setNull(_index, Types.SMALLINT); 
     } else { 
      _ps.setLong(_index, ((MarshallableIdEnum) _value).getId()); 
     } 
     } catch (ClassCastException e) { 
     throw new IllegalStateException(this.getClass().getName() + ", issue: " + _value + "/" + _index, e); 
     } 
    } 


    private static final int[] SQL_TYPES = {Types.SMALLINT}; 

    public int[] sqlTypes() { 
     return SQL_TYPES; 
    } 


    public Class returnedClass() { 
     return this.clazz; 
    } 

    @Override 
    public Object deepCopy(Object value) throws HibernateException { 
     return value; 
    } 

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

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

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

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

    @Override 
    public int hashCode(Object x) throws HibernateException { 
     return x.hashCode(); 
    } 

    @Override 
    public boolean equals(Object x, Object y) throws HibernateException { 
     return (x == y) || ((null != x) && (null != y) && x.equals(y)); 
    } 

} 

La colonne de la zone dans la table d'adresses est définie comme:

+--------------+-----------------------+------+-----+-------------------+-----------------------------+ 
| Field  | Type     | Null | Key | Default   | Extra      | 
+--------------+-----------------------+------+-----+-------------------+-----------------------------+       | 
| are_id  | smallint(5) unsigned | YES | MUL | NULL          | 
+--------------+-----------------------+------+-----+-------------------+-----------------------------+ 

Juste pour clarifier les données est tous là dans le tableau.

En parcourant le code, il semble que dans le HibernateAreaEnumType le rs.wasNull() est de retour true mais en regardant les données retournées par l'sql select (en utilisant P6Spy) montre que les informations de zone ENUM est là.

Toute aide vraiment apprécié

Répondre

0

Le problème était que je fondamentalement ne comprenais pas ce que l'appel ResultSet.wasNull() indiqué.

A savoir qu'il "indique si la dernière colonne lue a une valeur SQL NULL". .

https://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html

Et pas s'il y avait un jeu de résultats vide (ce qui est ce que je pensais déjà

En undestanding cela, je changé la méthode nullSafeGet de:

@Override 
    public Object nullSafeGet(ResultSet _rs, String[] _names, SessionImplementor _sessionImplementor, Object _owner) throws HibernateException, SQLException { 

     Object result = null; 

     if (!_rs.wasNull()) { 
     Long enumId = (long) _rs.getInt(_names[0]); 
     try { 
      result = this.parseMethod.invoke(null, enumId); 
     } catch (Exception e) { 
      throw new HibernateException("issue trying to method to parse value to make enum: " + enumId, e); 
     } 
     } 

     return result; 
    } 

à

@Override 
    public Object nullSafeGet(ResultSet _rs, String[] _names, SessionImplementor _sessionImplementor, Object _owner) throws HibernateException, SQLException { 

     Object result = null; 
     Short shortId = StandardBasicTypes.SHORT.nullSafeGet(_rs, _names[0], _sessionImplementor); 

     if (shortId != null) { 
     log.debug("setting: " + _names[0] + " : " + _rs.wasNull() + " : " + _owner); 
     Long enumId = shortId.longValue(); 
     try { 
      result = this.parseMethod.invoke(null, enumId); 
     } catch (Exception e) { 
      throw new HibernateException("issue trying to method to parse value to make enum: " + enumId, e); 
     } 
     } else { 
     result = null; 
     } 

     return result; 
    } 

Et puis cela a fonctionné.