【问题标题】:Java Hibernate Transformer AliasToBeanNestedResultTransformerJava Hibernate 转换器 AliasToBeanNestedResultTransformer
【发布时间】:2013-12-18 08:54:13
【问题描述】:

我有一个这样的查询。我通过学生证我需要学生及其父母的一些字段以及父母的一些字段->地址[这是我面临的主要问题]我正在使用AliasToBeanNestedResultTransformer变压器Sami Andoni

这里是它的实现CODE

这是我的代码。

public List<Student>searchForStudent(Integer studentId)
{           
    Projection p=Projections.projectionList().create()
    .add(Projections.property("name"),"name")//the student name it works O.K
    .add(Projections.property("lastname"),"lastname")//the student name it works O.K
    .add(Projections.property("age"),"age")//the student AGE it works O.K                
    .add(Projections.property("p.phone"),"parent.phone")//the parent phone it works O.K                
    .add(Projections.property("address.state").as("parent.Address.state")); // i need a field from address.state here is the problem...  
    Session session = ......
    Criteria like = session.createCriteria(Student.class).add(prepareForSelect())//some filters..
    .createAlias("parent","p")//the parent of the student. a student have one parent
    .createAlias("parent.Address","address")//the address of the parent.... a parent have one address.
    .setProjection(p)                
    .setResultTransformer(new AliasToBeanNestedResultTransformer(Student.class));    
    List<Student>results=like.list();   
    return results;     
}         

它抛出

Exception in thread "main" org.hibernate.PropertyAccessException:   IllegalArgumentException occurred while calling setter of com.generic.model.Parent.Address

仅供参考是某种类型不匹配,我在SAMI 代码中进行了一些跟踪,我看到了这个

[MyState]
[Address]

在这种情况下,Hibernate 似乎返回了 String State MyState,而转换器使用的是 Address Object,这是 type Mismatch.

急需什么帮助吗

非常感谢。

【问题讨论】:

    标签: java hibernate transformer


    【解决方案1】:

    我改进了 SamiAndoni 课程,也许它可以解决您的问题

    package com.alutiiq.develop.promanagesys.core.util;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.ParameterizedType;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import org.hibernate.HibernateException;
    import org.hibernate.property.PropertyAccessor;
    import org.hibernate.property.PropertyAccessorFactory;
    import org.hibernate.property.Setter;
    import org.hibernate.transform.AliasToBeanResultTransformer;
    import org.hibernate.transform.AliasedTupleSubsetResultTransformer;
    import org.hibernate.transform.ResultTransformer;
    
    /**
     * Help to transform alises with nested alises
     * 
     * @author Miguel Resendiz
     * 
     */
    public class AliasToBeanNestedResultTransformer extends
        AliasedTupleSubsetResultTransformer {
    
        private static final long serialVersionUID = -8047276133980128266L;
    
        private static final int TUPE_INDEX = 0;
        private static final int ALISES_INDEX = 1;
        private static final int FIELDNAME_INDEX = 2;
    
        private static final PropertyAccessor accessor = PropertyAccessorFactory
            .getPropertyAccessor("property");
    
        private final Class<?> resultClass;
    
        private Object[] entityTuples;
        private String[] entityAliases;
    
        private Map<String, Class<?>> fieldToClass = new HashMap<String, Class<?>>();
        private Map<String, List<?>> subEntities = new HashMap<String, List<?>>();
        private List<String> nestedAliases = new ArrayList<String>();
        private Map<String, Class<?>> listFields = new HashMap<String, Class<?>>();
    
        public boolean isTransformedValueATupleElement(String[] aliases,
            int tupleLength) {
        return false;
        }
    
        public AliasToBeanNestedResultTransformer(Class<?> resultClass) {
    
        this.resultClass = resultClass;
        }
    
        public Object transformTuple(Object[] tuple, String[] aliases) {
    
        handleSubEntities(tuple, aliases);
        cleanParams(tuple, aliases);
        ResultTransformer rootTransformer = new AliasToBeanResultTransformer(
            resultClass);
        Object root = rootTransformer.transformTuple(entityTuples,
            entityAliases);
    
        loadSubEntities(root);
    
        cleanMaps();
        return root;
        }
    
        private void handleSubEntities(Object[] tuple, String[] aliases)
            throws HibernateException {
        String fieldName = "";
        String aliasName = "";
        try {
            for (int i = 0; i < aliases.length; i++) {
            String alias = aliases[i];
            if (alias.contains(".")) {
    
                String[] sp = alias.split("\\.");
                StringBuilder aliasBuilder = new StringBuilder();
                for (int j = 0; j < sp.length; j++) {
                if (j == 0) {
                    fieldName = sp[j];
                } else {
                    aliasBuilder.append(sp[j]);
                    aliasBuilder.append(".");
                }
                }
                aliasName = aliasBuilder.substring(0,
                    aliasBuilder.length() - 1);
    
                nestedAliases.add(alias);
                manageEntities(fieldName, aliasName, tuple[i]);
            }
            }
        } catch (NoSuchFieldException e) {
            throw new HibernateException("Could not instantiate resultclass: "
                + resultClass.getName() + " for field name: " + fieldName
                + " and alias name:" + aliasName);
        }
        }
    
        private Class<?> findClass(String fieldName) throws NoSuchFieldException,
            SecurityException {
        if (fieldToClass.containsKey(fieldName)) {
            return fieldToClass.get(fieldName);
        } else {
            Class<?> subclass = resultClass.getDeclaredField(fieldName)
                .getType();
    
            if (subclass.equals(List.class) || subclass.equals(Set.class)) {
            if (subclass.equals(List.class)) {
                listFields.put(fieldName, LinkedList.class);
            } else {
                listFields.put(fieldName, HashSet.class);
            }
            Field field = resultClass.getDeclaredField(fieldName);
            ParameterizedType genericType = (ParameterizedType) field
                .getGenericType();
            subclass = (Class<?>) genericType.getActualTypeArguments()[0];
    
            }
            fieldToClass.put(fieldName, subclass);
            return subclass;
        }
        }
    
        @SuppressWarnings("unchecked")
        private void manageEntities(String fieldName, String aliasName,
            Object tupleValue) throws NoSuchFieldException, SecurityException {
        Class<?> subclass = findClass(fieldName);
        if (!subEntities.containsKey(fieldName)) {
            List<Object> list = new ArrayList<Object>();
            list.add(new ArrayList<Object>());
            list.add(new ArrayList<String>());
            list.add(FIELDNAME_INDEX, subclass);
            subEntities.put(fieldName, list);
        }
        ((List<Object>) subEntities.get(fieldName).get(TUPE_INDEX))
            .add(tupleValue);
        ((List<String>) subEntities.get(fieldName).get(ALISES_INDEX))
            .add(aliasName);
        }
    
        private void cleanParams(Object[] tuple, String[] aliases) {
        entityTuples = new Object[aliases.length - nestedAliases.size()];
        entityAliases = new String[aliases.length - nestedAliases.size()];
    
        for (int j = 0, i = 0; j < aliases.length; j++) {
            if (!nestedAliases.contains(aliases[j])) {
            entityTuples[i] = tuple[j];
            entityAliases[i] = aliases[j];
            ++i;
            }
        }
        }
    
        @SuppressWarnings({ "unchecked", "rawtypes" })
        private void loadSubEntities(Object root) throws HibernateException {
        try {
            for (String fieldName : subEntities.keySet()) {
            Class<?> subclass = (Class<?>) subEntities.get(fieldName).get(
                FIELDNAME_INDEX);
    
            ResultTransformer subclassTransformer = new AliasToBeanNestedResultTransformer(
                subclass);
    
            Object subObject = subclassTransformer.transformTuple(
                ((List<Object>) subEntities.get(fieldName).get(0))
                    .toArray(),
                ((List<Object>) subEntities.get(fieldName).get(1))
                    .toArray(new String[0]));
    
            Setter setter = accessor.getSetter(resultClass, fieldName);
            if (listFields.containsKey(fieldName)) {
                Class<?> collectionClass = listFields.get(fieldName);
                Collection subObjectList = (Collection) collectionClass
                    .newInstance();
                subObjectList.add(subObject);
                setter.set(root, subObjectList, null);
            } else {
                setter.set(root, subObject, null);
            }
            }
        } catch (Exception e) {
            throw new HibernateException(e);
        }
        }
    
        private void cleanMaps() {
        fieldToClass = new HashMap<String, Class<?>>();
        subEntities = new HashMap<String, List<?>>();
        nestedAliases = new ArrayList<String>();
        listFields = new HashMap<String, Class<?>>();
        }
    
    }
    

    希望对你有帮助。

    -------------编辑 07/25/15---------------

    对嵌套列表进行分组。

    public List<? extends Entity<?>> cleanList(
            List<? extends Entity<?>> resultList) throws DataException {
        List<Entity<?>> entities = new ArrayList<Entity<?>>();
        Entity<?> current = null;
        try {
            for (Entity<?> entity : resultList) {
            if (entity.getId() == null) {
                continue;
            }
            if (current == null) {
                current = entity;
                continue;
            }
            if (current.getId().equals(entity.getId())) {
                append(current, entity);
            } else {
                entities.add(current);
                current = entity;
            }
            }
            if (current != null) {
            entities.add(current);
            }
            cleanSubList(entities);
            return entities;
        } catch (Exception e) {
            throw new DataException(e);
        }
        }
    
        @SuppressWarnings({ "rawtypes", "unchecked" })
        public Set<? extends Entity<?>> cleanList(
            Set<? extends Entity<?>> resultList) throws DataException {
            List listToClean = new LinkedList();
            listToClean.addAll(resultList);
            listToClean = cleanList(listToClean);
            resultList.clear();
            resultList.addAll(listToClean);
            return resultList;
        }
    
        @SuppressWarnings({ "unchecked", "rawtypes" })
        private void append(Entity<?> current, Entity<?> next)
            throws IllegalArgumentException, IllegalAccessException {
        Field[] fields = current.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (field.getType().equals(List.class)) {
            field.setAccessible(true);
            List valueNext = (List) field.get(next);
            List valueCurrent = (List) field.get(current);
            if (valueNext != null) {
                if (valueCurrent != null) {
                valueCurrent.addAll(valueNext);
                field.set(current, valueCurrent);
                } else {
                field.set(current, valueNext);
                }
            }
            } else if (field.getType().equals(Set.class)) {
            field.setAccessible(true);
            Set valueNext = (Set) field.get(next);
            Set valueCurrent = (Set) field.get(current);
            if (valueNext != null) {
                if (valueCurrent != null) {
                valueCurrent.addAll(valueNext);
                field.set(current, valueCurrent);
                } else {
                field.set(current, valueNext);
                }
            }
            }
        }
    
        }
    
        @SuppressWarnings({ "rawtypes", "unchecked" })
        private void cleanSubList(List<? extends Entity<?>> listToClean)
            throws IllegalArgumentException, IllegalAccessException,
            DataException {
                for (Entity<?> entity : listToClean) {
                    Field[] fields = entity.getClass().getDeclaredFields();
                    for (Field field : fields) {
                        if (field.getType().equals(List.class)) {
                            field.setAccessible(true);
                            List valueToClean = (List) field.get(entity);
                            // Throw a thread
                            if (valueToClean != null) {
                                valueToClean = cleanList(valueToClean);
                                field.set(entity, valueToClean);
                            }
                            } else if (field.getType().equals(Set.class)) {
                                field.setAccessible(true);
                                Set valueToClean = (Set) field.get(entity);
                                // Throw a thread
                                if (valueToClean != null) {
                                    valueToClean = cleanList(valueToClean);
                                    field.set(entity, valueToClean);
                                }
                            }
    
                    }
                }
        }
    

    为了加快进程,我建议在主进程中抛出一个线程。

    这是我的实体界面:

    package com.alutiiq.develop.promanagesys.common.entity;
    
    import java.io.Serializable;
    
    /**
     * Entity for Hibernate comunications
     * 
     * @author Miguel Resendiz
     * 
     * @param <I>
     *            Primary key type
     */
    public interface Entity<I extends Serializable> extends Serializable {
    
        /**
         * Enable poissibility to write generic queries using primary key
         * 
         * @return primary key value for entity
         */
        I getId();
    
        void setId(I id);
    
        void setId(String id);
    
    }
    

    使用示例:

    criteria.setResultTransformer(new AliasToBeanNestedResultTransformer(
        entityClass));
    List<Project> projects = criteria.list();
    projects = (List<Project>) cleanList(projects);
    

    【讨论】:

    • 你是如何改进它的?
    • 我实现了从 Map 搜索以避免查找 cass 类型的时间。我为多个嵌套 bean 实现了多个级别,并支持嵌套 List 和 Set bean。我的改进解决了这个问题: parent.Address.state 但是一对多(集合)关系的查询存在问题。因为此代码为每个连接匹配生成一个元素。但是如果你想要我有解决它的代码
    • @MiguelResendiz,嗨,我在我的项目中使用你修改的代码已经很长时间了。它适用于一对一的关系。但就像你说的那样,它不会将嵌套的对象列表分组到一个列表中,而是为列表中的每个嵌套对象生成一个单独的行。您是否有一个工作代码可以支持将嵌套列表分组到一个列表中,而不是生成一个单独的父行?谢谢..
    • 是的,我有。我将把它附加到答案中。
    猜你喜欢
    • 1970-01-01
    • 2018-04-23
    • 2013-12-24
    • 1970-01-01
    • 2015-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多