While this may be a bug, it isn’t directly related to any Envers.
The reason this occurs when a user uses Envers is because the audit framework relies heavily on a specific mapping mode offered by Hibernate ORM called dynamic-map. Essentially, all the audit mappings are type-less and therefore Hibernate treats the data as map-of-maps.
Why is Map considered a managed type?
I think the team agrees that when a dynamic-map mapping is in play, there is no java-type. In fact, we’ve specifically made changes in the run-time and meta model for Hibernate 6 that supports this view.
But as for 5.x, I want to look back at what we did specifically when we released 5.0. Has the meta model always dictated that for dynamic-map mappings, the java-type is java.util.Map? If it has, then I’m a bit reluctant to change that behavior in 5.x as that could have an impact on other applications.
So I think this definitely a bug, but not necessarily from the same perspective you have.
I took a very simple audited entity here (not fancy at all)
@Audited
@Entity
public class SimpleEntity {
@Id
@GeneratedValue
private Integer id;
}
In 5.0, the meta-model generated consisted of 4 managed types
ManagedType
EntityName
JavaType
MapType
Origin
Entity
SimpleEntity
com.package.SimpleEntity
POJO
ORM
Entity
DefaultRevisionEntity
o.h.envers.DefaultRevisionEntity
POJO
Envers
Entity
SimpleEntity_AUD
null
MAP
Envers
Embeddable
n/a
java.util.Map
MAP
Envers
This makes sense because the first two rows are actual mapped entities and the last two represent the map mode data for the audited entity SimpleEntity_AUD and its associated embeddable identifier.
Due to recent changes to the meta-model generation, 5.3/5.4 now only show 3 managed types
ManagedType
EntityName
JavaType
MapType
Origin
Entity
SimpleEntity
com.package.SimpleEntity
POJO
ORM
Entity
DefaultRevisionEntity
o.h.envers.DefaultRevisionEntity
POJO
Envers
Embeddable
n/a
java.util.Map
MAP
Envers
This leads me to a series of questions
Why is the SimpleEntity_AUD entity managed type no longer present?
If (1) is intended, then the associated embeddables for that parent entity-type should not exist either.
While this highlights some recent differences in the meta-model generation step, I still need a clearer understanding from spring-data’s perspective why this is even problematic.
We try to use the list of managed types to decide if we need to pass a target class to the JPA implementation when executing a query coming from a @Query annotation.
If the return type of the method is a managed type we assume the user wrote the query in such a way that JPA returns that entity.
If not we request a Tuple and construct the result ourself.
Mapsuddenly appearing in the managed types makes Map-returning-methods behave differently (and actually fail) depending on the usage of Envers.
I guess on our side we do have a couple of options to fine tune that check:
only consider ManageTypes that have a JavaType and an EntityName
or just those with origin ORM. Depending on what is available in the API
special handling for Maps
come to my mind.
I guess the real problem is that I so far didn’t find a clear definition what being a managed type even mean exactly. Preferably that would come from the JPA spec of course.
This effectively eliminates the Map embeddable because you filter based solely on ENTITY and then it also eliminates the dynamic-map entity types which have no java-type.
As a follow-up, in 5.0 / 5.1, we built the metamodel slightly different than we did in 5.2+ when we merged the JPA artifact as a part of Hibernate Core. Prior to 5.2, users could use the following to filter the Envers obtains from the metamodel if they wished:
If you set that setting to enabled, then the metamodel was populated with dynamic-map objects. But I believe even when using the ignoreUnsupported setting, this ultimately lead to the 5.2+ outcome where the dynamic-map entity type was filtered but any embeddable-type that had that entity-type as a parent was not.
So for 5.2+ we have 2 options:
Exclude the embeddables owned by a dynamic-map entity-type which is also excluded.
Include dynamic-map entity-types like we did prior to 5.2.
As a workaround, i used setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP), it makes query return list of maps. That method is deprecated though, AFAIK, there is no recommended replacement.
@schauder, after discussing this internally we agree that we need to revert this behavior to the 5.1 and prior way of dealing with dynamic-map based entity types where the configuration settings influence how the metamodel is to be built. So ultimately we’ll be going with (2) and will be handled in HHH-12871.