2015-10-30 1 views
7

Ce code:Mise en veille prolongée donne une étrange exception ClassCast (utilisant des transformateurs)

@Override 
public List<FactCodeDto> getAllFactsWithoutParentsAsFactDto() { 
    String completeQuery = FactCodeQueries.SELECT_DTO_FROM_FACT_WITH_NO_PARENTS; 
    Query query = createHibernateQueryForUnmappedTypeFactDto(completeQuery); 

    List<FactCodeDto> factDtoList = query.list(); //line 133 
    return factDtoList; 
} 

appeler cette méthode:

private Query createHibernateQueryForUnmappedTypeFactDto(String sqlQuery) throws HibernateException { 
    return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(Transformers.aliasToBean(FactCodeDto.class)); 
} 

me donne un ClassCastException -> une partie de la trace:

Caused by: java.lang.ClassCastException: be.fgov.just.cjr.dto.FactCodeDto cannot be cast to java.util.Map 
    at org.hibernate.property.access.internal.PropertyAccessMapImpl$SetterImpl.set(PropertyAccessMapImpl.java:102) 
    at org.hibernate.transform.AliasToBeanResultTransformer.transformTuple(AliasToBeanResultTransformer.java:78) 
    at org.hibernate.hql.internal.HolderInstantiator.instantiate(HolderInstantiator.java:75) 
    at org.hibernate.loader.custom.CustomLoader.getResultList(CustomLoader.java:435) 
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2423) 
    at org.hibernate.loader.Loader.list(Loader.java:2418) 
    at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:336) 
    at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:1898) 
    at org.hibernate.internal.AbstractSessionImpl.list(AbstractSessionImpl.java:318) 
    at org.hibernate.internal.SQLQueryImpl.list(SQLQueryImpl.java:125) 
    at be.fgov.just.cjr.dao.factcode.FactCodeDAOImpl.getAllFactsWithoutParentsAsFactDto(FactCodeDAOImpl.java:133) 

Ce qui est assez étrange car, en effet, si vous recherchez le code source d'Hibernate, il essaie de le faire:

@Override 
@SuppressWarnings("unchecked") 
public void set(Object target, Object value, SessionFactoryImplementor factory) { 
    ((Map) target).put(propertyName, value); //line 102 
} 

Ce qui ne fait aucun sens ...

cible

est de type Class et ce code tente de le jeter à la carte,

pourquoi faut-il essayer de le faire ???

tous les pointeurs sont plus que bienvenus ...

J'utilise Hibernate 5 (et je mise à niveau de 3) ...

edit: J'utilise aussi Spring (4.2.1.RELEASE; la mise à niveau également), qui appelle ces méthodes sur Deploy, tous les pointeurs de débogage sont les bienvenus et ...

modifier 2: (toute la classe FactCodeDto, comme l'a demandé)

package be.fgov.just.cjr.dto; 

import be.fgov.just.cjr.model.FactCode; 
import be.fgov.just.cjr.model.FactCodeType; 
import be.fgov.just.cjr.utility.FullDateUtil; 
import be.fgov.just.cjr.utility.Locales; 
import lombok.Getter; 
import lombok.Setter; 
import lombok.ToString; 
import org.springframework.util.Assert; 

import java.util.*; 

@Getter 
@Setter 
@ToString 
public class FactCodeDto extends TreeNodeValue { 

    private String cdFact; 
    private String cdFactSuffix; 
    private Boolean isSupplementCode; 
    private Boolean isTitleCode; 
    private Boolean mustBeFollowed; 

    private Date activeFrom; 
    private Date activeTo; 
    private Boolean isCode; 
    private Long idFact; 
    private Long idParent; 
    private String type; 
    Map<Locale, String> description = new HashMap<Locale, String>(3); 

    public FactCodeDto() { 
    } 

    public FactCodeDto(String prefix, String suffix) { 
     super(); 
     this.cdFact = prefix; 
     this.cdFactSuffix = suffix; 
    } 

    public FactCodeDto(String cdFact, String cdFactSuffix, Boolean isSupplementCode, Boolean mustBeFollowed) { 
     super(); 
     this.cdFact = cdFact; 
     this.cdFactSuffix = cdFactSuffix; 
     this.isSupplementCode = isSupplementCode; 
     this.mustBeFollowed = mustBeFollowed; 

    } 

    public FactCodeDto(String cdFact, String cdFactSuffix, Boolean isSupplementCode, Boolean mustBeFollowed, Long idFact, Long idParent, Boolean isCode, Boolean isTitleCode, Date from, Date to, Map<Locale, String> descriptions,String type) { 
     super(); 
     this.cdFact = cdFact; 
     this.cdFactSuffix = cdFactSuffix; 
     this.isSupplementCode = isSupplementCode; 
     this.mustBeFollowed = mustBeFollowed; 
     this.idFact = idFact; 
     this.idParent = idParent; 
     this.isCode = isCode; 
     this.isTitleCode = isTitleCode; 
     this.activeFrom = from; 
     this.activeTo = to; 
     if (descriptions != null) { 
      this.description = descriptions; 
     } 

     this.type = type; 

    } 

    public FactCodeDto(FactCode fc) { 
     this(fc.getPrefix(), fc.getSuffix(), fc.isSupplementCode(), fc.isHasMandatorySupplCodes(), fc.getId(), fc.getParent(), fc.isActualCode(), fc.isTitleCode(), fc.getActiveFrom(), fc.getActiveTo(), fc.getAllDesc(),fc.getType().getCode()); 
    } 

    public String formatCode() { 
     return FactCode.formatCode(cdFact, cdFactSuffix); 
    } 

    public boolean isActive() { 
     Date now = new Date(System.currentTimeMillis()); 
     return FullDateUtil.isBetweenDates(now, this.activeFrom, this.activeTo); 

    } 

    public void setDescFr(String s) { 
     description.put(Locales.FRENCH, s); 
    } 

    public void setDescNl(String s) { 
     description.put(Locales.DUTCH, s); 
    } 

    public void setDescDe(String s) { 
     description.put(Locales.GERMAN, s); 
    } 

    /** 
    * public String toString() { 
    * StringBuilder sb = new StringBuilder(); 
    * sb.append(getIdFact() + ": ") 
    * .append(getIdParent() + ": ") 
    * .append(" " + cdFact + cdFactSuffix + ": " + (isSupplementCode ? "NO Principal " : " Principal ")) 
    * .append((mustBeFollowed ? " Must Be Followed " : "NOT Must Be Followed ")); 
    * return sb.toString(); 
    * } 
    */ 

    public Map<Locale, String> getDescription() { 
     return description; 
    } 

    @Override 
    public int hashCode() { 
     final int prime = 31; 
     int result = 1; 
     String fullCode = formatCode(); 
     result = prime * result + ((fullCode == null) ? 0 : fullCode.hashCode()); 
     return result; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (this == obj) { 
      return true; 
     } 
     if (obj == null) { 
      return false; 
     } 
     if (getClass() != obj.getClass()) { 
      return false; 
     } 
     FactCodeDto other = (FactCodeDto) obj; 

     return formatCode().equals(other.formatCode()); 
    } 

    @Override 
    public boolean isChildOf(TreeNodeValue value) { 
     Assert.notNull(value); 
     boolean isChild = false; 
     if (value instanceof FactCodeDto) { 
      if (this.getIdParent() != null) { 
       isChild = this.getIdParent().equals(((FactCodeDto) value).getIdFact()); 
      } 

     } 
     return isChild; 
    } 

    @Override 
    public boolean isBrotherOf(TreeNodeValue value) { 
     Assert.notNull(value); 
     boolean isBrother = false; 
     if (value instanceof FactCodeDto) { 
      if (this.getIdParent() != null) { 
       isBrother = this.getIdParent().equals(((FactCodeDto) value).getIdParent()); 
      } 

     } 
     return isBrother; 
    } 

    @Override 
    public boolean isParentOf(TreeNodeValue value) { 
     Assert.notNull(value); 
     boolean isParent = false; 
     if (value instanceof FactCodeDto) { 
      isParent = this.getIdFact().equals(((FactCodeDto) value).getIdParent()); 
     } 
     return isParent; 
    } 


    @Override 
    public int compareTo(TreeNodeValue to) { 
     if (to instanceof FactCodeDto) { 
      return formatCode().compareTo(((FactCodeDto) to).formatCode()); 
     } else return 1; 

    } 


    public String getCode() { 
     return formatCode(); 
    } 


} 
+0

Votre cible que vous obtenez est de type: be.fgov.just.cjr.dto.FactCodeDto qui n'est pas une carte –

+2

Oui, je sais, mais je veux pour obtenir une liste de type FactCodeDto et 'tell' pour hiberner via setResultTransformer (Transformers.aliasToBean (FactCodeDto.class)) mais ensuite (pour une raison étrange) Hibernate essaye en interne de transformer ma FactCodeDto.class (target) en Map. .. mais il ne devrait pas faire cela, pourquoi fait-il cela? – Bamboomy

+0

pourquoi utiliser tout ce gonflement quand un simple hql ou des critères le résoudrait? – javaguest

Répondre

1

en fin de compte w asn't si difficile de trouver une solution,

Je viens de créer mon propre (personnalisé) ResultTransformer et précise que dans la méthode setResultTransformer:

private Query createHibernateQueryForUnmappedTypeFactDto(String sqlQuery) throws HibernateException { 
    return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(new FactCodeDtoResultTransformer()); 
    //return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(Transformers.aliasToBean(FactCodeDto.class)); 
} 

le code du transformateur de résultat personnalisé:

package be.fgov.just.cjr.dao.factcode; 

import be.fgov.just.cjr.dto.FactCodeDto; 

import java.util.Date; 
import java.util.List; 

/** 
* Created by a162299 on 3-11-2015. 
*/ 
public class FactCodeDtoResultTransformer implements org.hibernate.transform.ResultTransformer { 

    @Override 
    public Object transformTuple(Object[] objects, String[] strings) { 

     FactCodeDto result = new FactCodeDto(); 

     for (int i = 0; i < objects.length; i++) { 
      setField(result, strings[i], objects[i]); 
     } 

     return result; 
    } 

    private void setField(FactCodeDto result, String string, Object object) { 

     if (string.equalsIgnoreCase("cdFact")) { 
      result.setCdFact((String) object); 
     } else if (string.equalsIgnoreCase("cdFactSuffix")) { 
      result.setCdFactSuffix((String) object); 
     } else if (string.equalsIgnoreCase("isSupplementCode")) { 
      result.setIsSupplementCode((Boolean) object); 
     } else if (string.equalsIgnoreCase("isTitleCode")) { 
      result.setIsTitleCode((Boolean) object); 
     } else if (string.equalsIgnoreCase("mustBeFollowed")) { 
      result.setMustBeFollowed((Boolean) object); 
     } else if (string.equalsIgnoreCase("activeFrom")) { 
      result.setActiveFrom((Date) object); 
     } else if (string.equalsIgnoreCase("activeTo")) { 
      result.setActiveTo((Date) object); 
     } else if (string.equalsIgnoreCase("descFr")) { 
      result.setDescFr((String) object); 
     } else if (string.equalsIgnoreCase("descNl")) { 
      result.setDescNl((String) object); 
     } else if (string.equalsIgnoreCase("descDe")) { 
      result.setDescDe((String) object); 
     } else if (string.equalsIgnoreCase("type")) { 
      result.setType((String) object); 
     } else if (string.equalsIgnoreCase("idFact")) { 
      result.setIdFact((Long) object); 
     } else if (string.equalsIgnoreCase("idParent")) { 
      result.setIdParent((Long) object); 
     } else if (string.equalsIgnoreCase("isCode")) { 
      result.setIsCode((Boolean) object); 
     } else { 
      throw new RuntimeException("unknown field"); 
     } 

    } 

    @Override 
    public List transformList(List list) { 
     return list; 
    } 
} 

en hibernate 3 vous pouvez définir Aliasses aux requêtes mais vous ne pouvez plus le faire en hibernate 5 (corrigez-moi si je me trompe) donc l'aliasToBean est quelque chose que vous ne pouvez utiliser qu'en utilisant aliasses; ce que je n'ai pas fait, d'où l'exception.

+0

Il est possible d'utiliser des alias, voir ma réponse http://stackoverflow.com/a/37437567/3405171 –

+0

Et il est possible de faire un transformateur plus simple et universel, en utilisant la réflexion. –

4

J'ai trouvé que AliasToBean a changé dans Hibernate 5. Pour moi, l'ajout de getter pour mon domaine a résolu le problème.

+0

pour moi dans des conditions similaires, je devais changer le nom du champ de laisser dire «zipcode» à «ZipCode» (aka chameau cas) et renommez la méthode setter en conséquence. mais de toute façon, le texte d'exception peut dérouter. – ashirman

3

Je fais quelques recherches sur cette question. Le problème est que Hibernate convertit les alias pour les noms de colonnes en majuscules - cdFact devient CDFACT.

Lire pour une plus profonde explication et solution ici: mapping Hibernate query results to custom class?

0

je recevais cette exception

Je l'ai appelé un des champs dans DTO comme « closedIndexValue » après avoir changé à "closedindexValue ", Le code fonctionnait très bien. Je pense que c'était dû au cas de la lettre" I ".

closedIndexValue -> non conforme camelcase closedindexValue -> camelcase bon

Mise en veille prolongée Version: - 5.2.4

0

Cette exception se produit lorsque les setters et getters et non mis en correspondance correctement aux noms de colonnes. Assurez-vous d'avoir les getters et setters corrects pour la requête (Corriger les noms et les types de données corrects). En savoir plus à ce sujet ici:

http://javahonk.com/java-lang-classcastexception-com-wfs-otc-datamodels-imagineexpirymodel-cannot-cast-java-util-map/

+0

Cette réponse ne fournit pas de solution, même si le mappage correct ne fonctionne pas. – Bamboomy