为TypedQuery指定的类型与自身不兼容

时间:2018-02-08 09:29:41

标签: java spring hibernate spring-boot

我对Spring&有问题休眠。我有以下方式的方法:

@Override
@Transactional
public List<SomeEntityClass> getSomeData(Integer someParam1, Long someParam2) {

    TypedQuery<SomeEntityClass> query = em.createQuery(
            "SELECT sec FROM SomeEntityClass sec " +
                    "WHERE sec.someField1 = :param1 " +
                    "AND sec.someField2 = :param2 ", SomeEntityClass.class);
    query.setParameter("param1", someParam1);
    query.setParameter("param2", someParam2);

    try {
        return query.getResultList();
    } catch (Exception e) {
        return new LinkedList<>();
    }
}

此方法是Web套接字处理程序的一部分,在收到消息时调用。但是,当它发生时,我得到以下错误:

org.springframework.dao.InvalidDataAccessApiUsageException: 
   Type specified for TypedQuery [some.package.subpackage.SomeEntityClass] is incompatible 
    with query return type [class some.package.subpackage.SomeEntityClass]

我找到了similar question,并且提供的答案表明正在从不同的类加载器加载类。但是:

ClassLoader a = UserMicroscopeLensLight.class.getClassLoader();
ClassLoader b = em.getClass().getClassLoader();

a.equals(b)

收益率

true


编辑:2018-02-08 14:05 CET

所以我通过代码调试并从字节代码反编译AbstractEntityManagerImpl.class并得到以下行:

if (!resultClass.isAssignableFrom(hqlQuery.getReturnTypes()[0].getReturnedClass())) {
    throw new IllegalArgumentException("Type specified for TypedQuery [" + resultClass.getName() + "] is incompatible with query return type [" + hqlQuery.getReturnTypes()[0].getReturnedClass() + "]");
}

resultClass.getClassLoader()给出了:

RestartClassLoader@9995

hqlQuery.getReturnTypes()[0].getReturnedClass().getClassLoader()(以及this.getClass().getClassLoader()导致:

Launcher$AppClassLoader@10034

有趣的是,在查询方法中调用em.getClass().getClassLoader()会导致:

RestartClassLoader@9995

所以我问...... WTF?!看看痕迹:

at org.hibernate.jpa.spi.AbstractEntityManagerImpl.resultClassChecking(AbstractEntityManagerImpl.java:387)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:344)
at sun.reflect.GeneratedMethodAccessor109.invoke(Unknown Source:-1)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
at com.sun.proxy.$Proxy109.createQuery(Unknown Source:-1)
at some.package.name.SomeDaoImpl.getSomeData(SomeDaoImpl.java:21)

Iit似乎,getSomeData中调用的实体管理器只是某些SharedEntityManager的代理,它们都有不同的类加载器......

2 个答案:

答案 0 :(得分:1)

这绝对看起来像是一个类加载器问题。要确认它,请尝试此代码片段。我只是将其作为答案发布,因为我无法将其纳入评论中。

for (EntityType e : em.getMetamodel().getEntities()) {
    if (e.getJavaType().getName().equals(SomeEntityClass.class.getName())) {
        assert(e.getJavaType().equals(SomeEntityClass.class));
    }
}

如果断言失败,那么该类确实加载了两次。

答案 1 :(得分:0)

确定。我发现了这个问题。删除spring dev工具解决了所有问题:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>

想法来自Spring's github issue