JadiraOrg/jadira

PersistentEnum should use proper mappedClass as returnedClass()

Closed this issue · 2 comments

Entity:

@Entity
public class Promo {

@Type(type = "org.jadira.usertype.corejava.PersistentEnum", parameters = @Parameter(name = "enumClass", value = "id.co.bippo.common.PromoKind"))
private PromoKind kind = null;

@Type(type = "org.jadira.usertype.corejava.PersistentEnum", parameters = @Parameter(name = "enumClass", value = "id.co.bippo.promotion.jpa.PromoScope"))
private PromoScope scope = null;

To use NEW with the following class:

public class PromoWithPositioner {

    public PromoWithPositioner(UUID id, PromoKind kind, @Nullable PromoScope scope, Integer positioner) {
        super();
        this.id = id;
        this.kind = kind;
        this.scope = scope;
        this.positioner = positioner;
    }

and the following query:

final String query = "SELECT NEW id.co.bippo.promotion.impl.PromoWithPositioner(p.id, p.kind, p.scope, p.positioner)"
        + " FROM Promo p";
final List<PromoWithPositioner> unsorted = em.createQuery(query, PromoWithPositioner.class).getResultList();

Hibernate complains:

org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate appropriate constructor on class [id.co.bippo.promotion.impl.PromoWithPositioner]. Expected arguments are: java.util.UUID, java.lang.Enum, java.lang.Enum, int [SELECT NEW id.co.bippo.promotion.impl.PromoWithPositioner(p.id, p.kind, p.scope, p.positioner) FROM id.co.bippo.promotion.jpa.Promo p]
     at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:91)
     at org.hibernate.hql.internal.ast.ErrorCounter.throwQueryException(ErrorCounter.java:109)
     at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:284)
     at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:206)
     at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:158)
     at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:131)
     at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:93)
     at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:167)
     at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:301)
     at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:236)
     at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1800)
     at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:342)
     at java.lang.reflect.Method.invoke(Method.java:483)
     at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:291)
     at com.sun.proxy.$Proxy141.createQuery(Unknown Source)
     at id.co.bippo.promotion.impl.JpaPromoRepository.findAllWithPositioner(JpaPromoRepository.java:426)
     at java.lang.reflect.Method.invoke(Method.java:483)
     at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
     at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
     at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
     at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:267)
     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
     at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
     at com.sun.proxy.$Proxy149.findAllWithPositioner(Unknown Source)
     at java.lang.reflect.Method.invoke(Method.java:483)
     at org.apache.wicket.proxy.LazyInitProxyFactory$JdkHandler.invoke(LazyInitProxyFactory.java:435)
     at com.sun.proxy.$Proxy191.findAllWithPositioner(Unknown Source)
     at id.co.bippo.promotion.web.ActionPromoLinkPanel$2.onClick(ActionPromoLinkPanel.java:90)

IMHO this is not correct, as when getting e.g. p.kind Hibernate knows that it is using user type PersistentEnum[enumClass=id.co.bippo.promotion.jpa.PromoKind], and getMappedClass() returns id.co.bippo.promotion.jpa.PromoKind.

However, returnedClass() should return getMappedClass() instead:

@Override
public Class<Enum<?>> returnedClass() {
    return (Class<Enum<?>>) getMappedClass();
}

There is a workaround, which uses Hibernate's expected signature:

public PromoWithPositioner(UUID id, Enum<PromoKind> kind, @Nullable Enum<PromoScope> scope, Integer positioner) {
    super();
    this.id = id;
    this.kind = (PromoKind) kind;
    this.scope = (PromoScope) scope;
    this.positioner = positioner;
}

Tag @ceefour

👍 for this :)

There is a fix for this about to be pushed to HEAD in GitHub