Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hibernate 'could not resolve property' issue with Composite ID / @IdClass #1436

Closed
msavy opened this issue Jan 25, 2022 · 9 comments · Fixed by #1438
Closed

Hibernate 'could not resolve property' issue with Composite ID / @IdClass #1436

msavy opened this issue Jan 25, 2022 · 9 comments · Fixed by #1438
Assignees
Labels
component: core kind: bug worth: high Implementing this has a high worth
Milestone

Comments

@msavy
Copy link

msavy commented Jan 25, 2022

Description

I'm trying to port Apiman to use BlazePersistence instead of the JPA Criteria API to avoid losing my mind with its bizarre syntax 😂.

However, I seem to have hit a blocker.

We use composite keys/ids in our model in a few places via @IdClass. This is something we can't change for compatibility reasons (unless there's a compatible workaround you are aware of).

It seems that the particular @Entity design we're using works fine with CriteriaAPI, standard Hibernate, etc, but trips up Blaze Persistence somehow. This may be related to #399, not sure?

The TL;DR is that it seems it can't traverse that ID properly, and the only thing I can think of is @IdClass.

Expected behaviour

Should be able to handle this @Entity sample's graph, as it works in Hibernate + Criteria API.

Actual behaviour

The error displayed is:

2022-01-25 16:02:15,899 ERROR [io.qua.run.Application] (Quarkus Main Thread) Failed to start application (with profile dev): org.hibernate.QueryException: could not resolve property: client.id of: io.apiman.manager.api.beans.clients.ClientVersionBean
	at org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:77)
	at org.hibernate.persister.entity.AbstractPropertyMapping.toType(AbstractPropertyMapping.java:71)
	at org.hibernate.persister.entity.AbstractEntityPersister.getPropertyType(AbstractEntityPersister.java:5124)
	at com.blazebit.persistence.integration.hibernate.base.HibernateJpaProvider.hasJoinCondition(HibernateJpaProvider.java:1414)
	at com.blazebit.persistence.impl.EntityMetamodelImpl$AttributeEntry.<init>(EntityMetamodelImpl.java:1060)
	at com.blazebit.persistence.impl.EntityMetamodelImpl.collectIdColumns(EntityMetamodelImpl.java:484)
	at com.blazebit.persistence.impl.EntityMetamodelImpl.collectColumnNames(EntityMetamodelImpl.java:394)
	at com.blazebit.persistence.impl.EntityMetamodelImpl.<init>(EntityMetamodelImpl.java:127)
	at com.blazebit.persistence.impl.CriteriaBuilderFactoryImpl.<init>(CriteriaBuilderFactoryImpl.java:110)
	at com.blazebit.persistence.impl.CriteriaBuilderConfigurationImpl.createCriteriaBuilderFactory(CriteriaBuilderConfigurationImpl.java:2018)
	at com.blazebit.persistence.integration.quarkus.runtime.EntityViewRecorder.lambda$criteriaBuilderFactorySupplier$0(EntityViewRecorder.java:56)
	at com.blazebit.persistence.CriteriaBuilderFactory_2f29ab4902e863bcf38a5a9ab37269748362ecdd_Synthetic_Bean.create(Unknown Source)
	at com.blazebit.persistence.CriteriaBuilderFactory_2f29ab4902e863bcf38a5a9ab37269748362ecdd_Synthetic_Bean.create(Unknown Source)
	at io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:96)
	at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:29)
	at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:26)
	at io.quarkus.arc.impl.LazyValue.get(LazyValue.java:26)
	at io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69)
	at io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:26)
	at com.blazebit.persistence.CriteriaBuilderFactory_2f29ab4902e863bcf38a5a9ab37269748362ecdd_Synthetic_Bean.get(Unknown Source)
	at com.blazebit.persistence.CriteriaBuilderFactory_2f29ab4902e863bcf38a5a9ab37269748362ecdd_Synthetic_Bean.get(Unknown Source)
	at org.acme.Main_Bean.create(Unknown Source)
	at org.acme.Main_Bean.create(Unknown Source)
	at io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:96)
	at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:29)
	at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:26)
	at io.quarkus.arc.impl.LazyValue.get(LazyValue.java:26)
	at io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69)
	at io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:26)
	at org.acme.Main_Observer_startup_f43ab41051de39ca1e534f6cd06115c3c9b219b8.notify(Unknown Source)
	at io.quarkus.arc.impl.EventImpl$Notifier.notifyObservers(EventImpl.java:320)
	at io.quarkus.arc.impl.EventImpl$Notifier.notify(EventImpl.java:302)
	at io.quarkus.arc.impl.EventImpl.fire(EventImpl.java:73)
	at io.quarkus.arc.runtime.ArcRecorder.fireLifecycleEvent(ArcRecorder.java:128)
	at io.quarkus.arc.runtime.ArcRecorder.handleLifecycleEvents(ArcRecorder.java:97)
	at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy_0(Unknown Source)
	at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy(Unknown Source)
	at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
	at io.quarkus.runtime.Application.start(Application.java:101)
	at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:104)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:67)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:41)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:120)
	at io.quarkus.runner.GeneratedMain.main(Unknown Source)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.Nati

Steps to reproduce

. https://www.github.com/msavy/reproducer-for-blazepersistence.git
. ./mvnw compile quarkus:dev (or whatever you prefer).
. First, see Main.java for bootstrapping, and then io.apiman.manager.api.beans.*
. @IdClass seems to work in some simpler setups, but not this one.

Environment

Please see reproducer for additional details, but:
Version: 1.6.5
JPA-Provider: Hibernate: 5.6.4
DBMS: com.h2database.h2-1.4.197.jar
Application Server: Quarkus

@msavy msavy changed the title Hibernate 'could not resolve property' issue with Composite ID Hibernate 'could not resolve property' issue with Composite ID / @IdClass Jan 25, 2022
@jwgmeligmeyling
Copy link
Collaborator

Is your Id property named “id”? I am asking because in Hibernate “id” is also used as a way to reference the IdClass object in queries, which may collide with your composite key.

It also could be related to Quarkus.

I am using IdClass with Blaze-Persistence core/criteria/querydsl all the time. The only known limitations wrt composite keys lie in entity views.

@msavy
Copy link
Author

msavy commented Jan 25, 2022

Thanks for your response @jwgmeligmeyling!

Is your Id property named “id”? I am asking because in Hibernate “id” is also used as a way to reference the IdClass object in queries, which may collide with your composite key.

If I understand you correctly, then yes. ClientBean in the reproducer, for example (src/main/java/io/apiman/manager/api/beans/clients/ClientBean.java) has a field called id which is part of the composite id.

It also could be related to Quarkus.

I used Quarkus solely for this reproducer as it was a very fast way with minimal additional file noise (the error is identical, however, on all platforms).

Apiman does not have a Quarkus distribution yet.

The current Apiman Manager distros are TomCat, WildFly, & Jetty.

It works fine when not using BlazePersistence, and the error occurs identically on all of the above, as far as I can ascertain.

I am using IdClass with Blaze-Persistence core/criteria/querydsl all the time. The only known limitations wrt composite keys lie in entity views.

Thanks. Interesting; I'll try fiddling with the reproducer some more to see if that makes any difference.

@beikov beikov added this to the 1.6.6 milestone Jan 25, 2022
@beikov beikov added component: core kind: bug worth: high Implementing this has a high worth labels Jan 25, 2022
@beikov beikov self-assigned this Jan 25, 2022
@beikov
Copy link
Member

beikov commented Jan 25, 2022

Hi @msavy, I'll look into this later this week as this is probably pretty easy to fix.

@msavy
Copy link
Author

msavy commented Jan 25, 2022

Wonderful, thanks @beikov - hopefully I can progress some other areas of the Apiman code in the meanwhile and cycle back onto this before I need to release upstream.

I guess I could use QueryDSL directly as a standin temporarily if needed and I run out of time before.

The code for the standard JPA Criteria API is just so bizarre that the other Apiman contributors couldn't understand it, and it was proving a nightmare to maintain.

I am using IdClass with Blaze-Persistence core/criteria/querydsl all the time. The only known limitations wrt composite keys lie in entity views.

Thanks. Interesting; I'll try fiddling with the reproducer some more to see if that makes any difference.

re: @jwgmeligmeyling's idea -- unfortunately I didn't have any luck by changing this around

@beikov
Copy link
Member

beikov commented Jan 26, 2022

Ok, so I looked into this and unfortunately this is a limitation of Hibernate when it comes to associations for entities with id classes. I created https://hibernate.atlassian.net/browse/HHH-15051 for this and already have a fix for Hibernate ready. I hope it's ok that you have to update Hibernate to 5.6.6.Final?

@msavy
Copy link
Author

msavy commented Jan 26, 2022

In the Apiman upstream we're using Hibernate 5.3.20.Final -- we generally track the version being used in the version of WildFly we support. I suppose I could try to force it to use a different version by using jboss modules, but I am not sure if that will break something else.

This particular relationship I've distilled in the reproducer has been in use in Apiman since about 2014 from what I can see. So I guess the Hibernate limitation only impacts applications such as BlazePersistence? It seems to have worked for years in terms of using Hibernate itself.

@beikov
Copy link
Member

beikov commented Jan 26, 2022

In the Apiman upstream we're using Hibernate 5.3.20.Final -- we generally track the version being used in the version of WildFly we support. I suppose I could try to force it to use a different version by using jboss modules, but I am not sure if that will break something else.

Ughh, I feared that this could be the case.

This particular relationship I've distilled in the reproducer has been in use in Apiman since about 2014 from what I can see. So I guess the limitation only impacts applications such as BlazePersistence? It seems to have worked for years in terms of using Hibernate itself.

Well, usually Hibernate allows access to the property types/columns etc. by property path per entity type. So usually, I can ask Hibernate for the type of client.id, but it seems that for associations with entitiy types that use an id class, it doesn't add these property paths.

I will implement a workaround for this limitation.

@msavy
Copy link
Author

msavy commented Jan 26, 2022

Well, usually Hibernate allows access to the property types/columns etc. by property path per entity type. So usually, I can ask Hibernate for the type of client.id, but it seems that for associations with entitiy types that use an id class, it doesn't add these property paths.

Aha, your explanation makes sense.

Thanks for that!

beikov added a commit to beikov/blaze-persistence that referenced this issue Jan 26, 2022
beikov added a commit that referenced this issue Jan 26, 2022
@msavy
Copy link
Author

msavy commented Jan 26, 2022

@beikov -- I can confirm that your fix works for Apiman using the 1.6.6.Final-SNAPSHOT build from #1438 / master (as of this post).

Hopefully when Apiman 3.x lands we'll be using BlazePersistence instead of JPA Criteria API.

A few small issues to iron out (re: pagination & ordering), but hopefully can get them figured out today.

Thanks again for your help 🎉.

beikov added a commit to beikov/blaze-persistence that referenced this issue Nov 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: core kind: bug worth: high Implementing this has a high worth
Projects
None yet
3 participants