# Why is java.util.Map a managed type for Hibernate when entity is audited?

**URL:** <https://discourse.hibernate.org/t/why-is-java-util-map-a-managed-type-for-hibernate-when-entity-is-audited/1113>\
**Category:** Hibernate ORM\
**Created:** [July 25, 2018, 1:00pm UTC](https://discourse.hibernate.org/t/why-is-java-util-map-a-managed-type-for-hibernate-when-entity-is-audited/1113 "2018-07-25T13:00:02Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![schauder](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/schauder/32/98_2.png) [@schauder](https://discourse.hibernate.org/u/schauder)\
**Post date:** [July 25, 2018, 1:00pm UTC](https://discourse.hibernate.org/t/why-is-java-util-map-a-managed-type-for-hibernate-when-entity-is-audited/1113/1 "2018-07-25T13:00:02Z")

</div>

If I list the managed types of Hibernate, when having only registered a single entity, I get that entity. As expected.

If I put a `@Audited` annotation on it I get two more managed types:

`class org.hibernate.envers.DefaultRevisionEntity` As expected.  
And `interface java.util.Map` which seems really weird.

Why is `Map` considered a managed type?

@vlad mentioned on [https://stackoverflow.com/q/51518740/66686](https://stackoverflow.com/q/51518740/66686) that this might be a bug and recommended to ping @Naros

This causes problems in Spring Data JPA as described here: [https://jira.spring.io/browse/DATAJPA-1384](https://jira.spring.io/browse/DATAJPA-1384) The issue also contains an example project.

Adding a test like this:

```
@Autowired
private EntityManager em;

@Test
public void mapIsNotAManagedType_IsIt(){

	Set<ManagedType<?>> types = em.getMetamodel().getManagedTypes();

	types.forEach(x -> System.out.println(x.getJavaType()));

	assertThat(types).extracting(ManagedType::getJavaType).doesNotContain((Class)Map.class);
}  

```

Demonstrates the behavior without Spring Data involvement.

---

<div class="post-metadata">

**Author:** ![Naros](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/naros/32/19_2.png) [@Naros](https://discourse.hibernate.org/u/Naros)\
**Post date:** [July 25, 2018, 4:13pm UTC](https://discourse.hibernate.org/t/why-is-java-util-map-a-managed-type-for-hibernate-when-entity-is-audited/1113/2 "2018-07-25T16:13:53Z")

</div>

> might be a bug and recommended to ping Naros

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.

I’ll get back to you.

---

<div class="post-metadata">

**Author:** ![Naros](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/naros/32/19_2.png) [@Naros](https://discourse.hibernate.org/u/Naros)\
**Post date:** [July 25, 2018, 5:48pm UTC](https://discourse.hibernate.org/t/why-is-java-util-map-a-managed-type-for-hibernate-when-entity-is-audited/1113/3 "2018-07-25T17:48:55Z")

</div>

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)

```auto
@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

1. Why is the `SimpleEntity_AUD` entity managed type no longer present?
2. 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.

---

<div class="post-metadata">

**Author:** ![schauder](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/schauder/32/98_2.png) [@schauder](https://discourse.hibernate.org/u/schauder)\
**Post date:** [July 26, 2018, 6:53am UTC](https://discourse.hibernate.org/t/why-is-java-util-map-a-managed-type-for-hibernate-when-entity-is-audited/1113/4 "2018-07-26T06:53:48Z")

</div>

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.

`Map` _suddenly_ 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 `Map`s

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.

---

<div class="post-metadata">

**Author:** ![Naros](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/naros/32/19_2.png) [@Naros](https://discourse.hibernate.org/u/Naros)\
**Post date:** [July 26, 2018, 3:22pm UTC](https://discourse.hibernate.org/t/why-is-java-util-map-a-managed-type-for-hibernate-when-entity-is-audited/1113/5 "2018-07-26T15:22:49Z")

</div>

> [@schauder](#):
>
> 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.

Then wouldn’t the following make more sense here for what you’re trying to accomplish?

```auto
List<ManagedType<?>> types = em.getMetamodel()
  .getManagedTypes()
  .stream()
  .filter( x -> { return x.getPersistenceType().equals( PersistenceType.ENTITY ) && x.getJavaType() != null; } )
  .collect( Collectors.toList() );

```

This would basically work for all 5.x releases.

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.

---

<div class="post-metadata">

**Author:** ![Naros](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/naros/32/19_2.png) [@Naros](https://discourse.hibernate.org/u/Naros)\
**Post date:** [July 26, 2018, 4:34pm UTC](https://discourse.hibernate.org/t/why-is-java-util-map-a-managed-type-for-hibernate-when-entity-is-audited/1113/6 "2018-07-26T16:34:20Z")

</div>

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:

```auto
hibernate.ejb.metamodel.population=ignoreUnsupported

```

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:

1. Exclude the embeddables owned by a dynamic-map entity-type which is also excluded.
2. Include dynamic-map entity-types like we did prior to 5.2.

---

<div class="post-metadata">

**Author:** ![darionis](https://avatars.discourse-cdn.com/v4/letter/d/e47774/32.png) [@darionis](https://discourse.hibernate.org/u/darionis)\
**Post date:** [July 26, 2018, 9:34pm UTC](https://discourse.hibernate.org/t/why-is-java-util-map-a-managed-type-for-hibernate-when-entity-is-audited/1113/7 "2018-07-26T21:34:28Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![schauder](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/schauder/32/98_2.png) [@schauder](https://discourse.hibernate.org/u/schauder)\
**Post date:** [July 27, 2018, 12:50pm UTC](https://discourse.hibernate.org/t/why-is-java-util-map-a-managed-type-for-hibernate-when-entity-is-audited/1113/8 "2018-07-27T12:50:25Z")

</div>

That’s what I basically ended up implementing.

Thanks.

---

<div class="post-metadata">

**Author:** ![Naros](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/naros/32/19_2.png) [@Naros](https://discourse.hibernate.org/u/Naros)\
**Post date:** [August 3, 2018, 4:48pm UTC](https://discourse.hibernate.org/t/why-is-java-util-map-a-managed-type-for-hibernate-when-entity-is-audited/1113/9 "2018-08-03T16:48:42Z")

</div>

@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](https://hibernate.atlassian.net/browse/HHH-12871).
