QueryArgumentException with polymorphic queries

Hi,
we’re migrating to Hibernate 6.2 from 5.6. There’s problem when we call query setParameter on polymorphic type in HQL.
The exact issue is when we call setParameter with a proxied entity and inside the HQL query “where” clause is referenced parent poylmorphic type. Then we get the QueryArgumentException.
This worked fine in version 5, but now there’s some kind of validation in setParameter method and it throws this exception. Is this a bug or how we should deal with this?
I mean we don’t want unproxy every entity that is used as a parameter, it should work without unproxying as it did before
See the snippet below with a inline comment inside testQuery test.

org.hibernate.query.QueryArgumentException: Argument [org.hibernate.orm.test.annotations.inheritance.ProxyTest$UserSiteImpl@20] of type [org.hibernate.orm.test.annotations.inheritance.ProxyTest$UserSiteImpl$HibernateProxy$pP2CT8sK] did not match parameter type [org.hibernate.orm.test.annotations.inheritance.ProxyTest$SiteImpl (n/a)]

@DomainModel(
        annotatedClasses = {
                ProxyTest.SiteImpl.class,
                ProxyTest.UserSiteImpl.class,
                ProxyTest.BarImpl.class,
                ProxyTest.BarBarImpl.class,
        }
)
@SessionFactory
public class ProxyTest {

    private Long siteId;

    @Test
    public void testQuery(SessionFactoryScope scope) {
        scope.inTransaction(session -> {
            UserSite userSite = session.getReference(UserSiteImpl.class, siteId);

            List<Bar> bars = session.createQuery("SELECT b FROM Bar b inner join b.site as site WHERE site = ?1")
                    .setParameter(1, userSite) // This call fails, it used to work in version 5
                    .list();
            BarImpl newBar = (BarImpl) bars.get(0);
            assertNotNull(newBar);
            assertNotNull(newBar.getSite());
            assertFalse(Hibernate.isInitialized(newBar.getSite()));
            assertEquals(siteId, newBar.getSite().getId());
        });
    }

    @BeforeEach
    public void setupData(SessionFactoryScope scope) {
        this.siteId = scope.fromTransaction(session -> {
            UserSiteImpl userSite = new UserSiteImpl();
            userSite.id = 1L;
            session.persist(userSite);

            BarImpl bar = new BarImpl();
            bar.id = 1L;
            bar.setSite(userSite);
            bar.setDetails("Some details");

            session.persist(bar);

            session.flush();

            assertNotNull(userSite.getId());
            assertEquals(userSite.getId(), bar.getSite().getId());

            return userSite.getId();
        });
    }

    @AfterEach
    public void cleanupData(SessionFactoryScope scope) {
        scope.inTransaction(session -> {
            session.delete(session.find(UserSiteImpl.class, siteId));
            session.delete(session.find(BarImpl.class, siteId));
        });
        this.siteId = null;
    }

    public interface EntityWithId {

        Long getId();
    }

    public interface Site extends EntityWithId {

    }

    public interface UserSite extends Site {

    }

    @Entity
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn(name = "TYPE", length = 20, discriminatorType = DiscriminatorType.STRING)
    @Proxy(proxyClass = Site.class)
    public static abstract class SiteImpl implements Site {

        @Id
        protected Long id;

        private String name;

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            Site foo = (Site) o;
            return id.equals(foo.getId());
        }

        @Override
        public int hashCode() {
            return Objects.hash(id);
        }
    }

    @Entity
    @DiscriminatorValue("USER_SITE")
    @Proxy(proxyClass = UserSite.class)
    public static class UserSiteImpl extends SiteImpl implements UserSite {
    }

    public interface Bar extends EntityWithId {

    }

    public interface SitedBar<S extends Site> extends Bar {

        S getSite();
    }

    @MappedSuperclass
    @Proxy(proxyClass = SitedBar.class)
    public static abstract class BarBarImpl<T extends Site> implements SitedBar<T> {

        @ManyToOne(fetch = FetchType.LAZY, targetEntity = SiteImpl.class)
        @JoinColumn(name = "BAR_ID")
        private Site site;

        @Override
        public T getSite() {
            return (T) site;
        }

        public void setSite(T site) {
            this.site = site;
        }

    }

    @Entity(name = "Bar")
    public static class BarImpl extends BarBarImpl<UserSite> implements Bar {

        @Id
        private Long id;

        private String details;

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getDetails() {
            return details;
        }

        public void setDetails(String details) {
            this.details = details;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            BarImpl bar = (BarImpl) o;
            return id.equals(bar.getId());
        }

        @Override
        public int hashCode() {
            return Objects.hash(id);
        }
    }
}
1 Like

I would say this is a bug.

Please try to create a reproducer with our test case template (https://github.com/hibernate/hibernate-test-case-templates/blob/master/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java) and if you are able to reproduce the issue, create a bug ticket in our issue tracker(https://hibernate.atlassian.net) and attach that reproducer.

1 Like

Reported as HHH-17510.

JIRA [HHH-17510] - Hibernate JIRA
Testcase PR Test case to reproduce proxy setParameter exception by mira-silhavy · Pull Request #338 · hibernate/hibernate-test-case-templates · GitHub