使用Hibernate返回自定义类型时报错的问题

数据库为oracle,在使用Hibernate查询时想要返回自定义的pojo类型,遇到类型转换的异常。如下面的命名查询希望返回数据行为typeClass类型

Query localQuery = session.getNamedQuery("findPersonInfo");
localQuery.setResultTransformer(Transformers.aliasToBean(typeClass)).list();//typeClass为目标pojo类型

运行后报错,错误信息如下:

java.lang.ClassCastException: com.test.pojo.TestPojo 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:434)
	at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2430)
	at org.hibernate.loader.Loader.list(Loader.java:2425)
	at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:335)
	at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:2153)
	at org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:987)
	at org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:148)
	at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1410)
TestPojo类如下:

public class TestPojo {
	private String id;
	private String username;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
}


原因是使用oracle时返回的字段默认为大写,导致转换失败。Hibernate可以通过自定义ResultTransformer类来解决这个问题,给出参考代码:

import java.lang.reflect.Field;
import java.util.List;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.hibernate.HibernateException;
import org.hibernate.transform.ResultTransformer;

/**
 * 
 * 修正hibernate返回自定义pojo类型时找不到属性的BUG
 * 主要发生在使用oracle时,查询返回的字段默认是大写的(除非SQL中指定了别名),这导致返回自定义pojo类型时会报找不到属性的错误,该类用于修正此BUG。
 * 使用该类时SQL返回的字段名大小写或者带"_"都会被忽略,如数据库字段为 USER_NAME,自定义pojo的属性名为username就可以使用
 * 
 *
 */
public class IgnoreCaseResultTransformer implements ResultTransformer {

    private static final long serialVersionUID = -3779317531110592988L;

    private final Class resultClass;
    private Field[] fields;
    private BeanUtilsBean beanUtilsBean;

    public IgnoreCaseResultTransformer(final Class resultClass) {
        this.resultClass = resultClass;
        this.fields = this.resultClass.getDeclaredFields();
        beanUtilsBean=BeanUtilsBean.getInstance();
    }

    /**
     * aliases为每条记录的数据库字段名,ORACLE字段名默认为大写
     * tupe为与aliases对应的字段的值
     */
    public Object transformTuple(final Object[] tuple, final String[] aliases) {
        Object result;
		try {
			result = this.resultClass.newInstance();
			for (int i = 0; i < aliases.length; i++) {
				for (Field field : this.fields) {
					String fieldName = field.getName();
					//数据库字段带下划线的时候也能保证使用,如数据库字段为 USER_NAME,自定义pojo的属性名为username就可以使用
					if (fieldName.equalsIgnoreCase(aliases[i].replaceAll("_", ""))) {
						beanUtilsBean.setProperty(result, fieldName, tuple[i]);
						break;
					}
				}
			}
		} catch (Exception e) {
			throw new HibernateException("Could not instantiate resultclass: " + this.resultClass.getName(), e);
		}
        return result;
    }

    @SuppressWarnings("rawtypes")
    public List transformList(final List collection) {
        return collection;
    }
}

使用方法:

Query localQuery = paramSession.getNamedQuery("findPersonInfo");
localQuery.setResultTransformer(new IgnoreCaseResultTransformer(typeClass)).list();//typeClass为目标pojo类型


参考:https://hibernate.atlassian.net/browse/HHH-5815

你可能感兴趣的:(找不到属性,hibernate自定义类型,hibernate,oracle,字段名大写,hibernate)