diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/ClassesAuditingData.java b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/ClassesAuditingData.java index f427e092dd..46d601450b 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/ClassesAuditingData.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/ClassesAuditingData.java @@ -115,8 +115,12 @@ public class ClassesAuditingData { if ( propertyAuditingData.getMapKeyEnumType() != null ) { final String referencedEntityName = MappingTools.getReferencedEntityName( property.getValue() ); - final ClassAuditingData referencedAuditingData = entityNameToAuditingData.get( referencedEntityName ); - addMapEnumeratedKey( property.getValue(), property.getPropertyAccessorName(), referencedAuditingData ); + if ( referencedEntityName != null ) { + // If no entity could be determined, this means the enum type isn't an entity mapping and instead is one + // to a basic type. In this use case, there is nothing special to do. + final ClassAuditingData referencedAuditingData = entityNameToAuditingData.get( referencedEntityName ); + addMapEnumeratedKey( property.getValue(), property.getPropertyAccessorName(), referencedAuditingData ); + } } // HHH-9108 diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/CollectionMetadataGenerator.java b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/CollectionMetadataGenerator.java index 0e3bc3bd11..b239396a86 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/CollectionMetadataGenerator.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/CollectionMetadataGenerator.java @@ -526,8 +526,9 @@ public final class CollectionMetadataGenerator { final IndexedCollection indexedValue = (IndexedCollection) propertyValue; final String mapKey = propertyAuditingData.getMapKey(); final EnumType mapKeyEnumType = propertyAuditingData.getMapKeyEnumType(); - if ( mapKey == null && mapKeyEnumType == null ) { - // This entity doesn't specify a javax.persistence.MapKey. Mapping it to the middle entity. + if ( ( mapKey == null && mapKeyEnumType == null ) || ( mapKeyEnumType != null && referencedEntityName == null ) ) { + // This entity doesn't specify a javax.persistence.MapKey or there is a MapKeyEnumerated but its a non-entity type. + // Mapping it to the middle entity. return addValueToMiddleTable( indexedValue.getIndex(), middleEntityXml, diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/collection/mapkey/MapKeyEnumeratedNonEntityTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/collection/mapkey/MapKeyEnumeratedNonEntityTest.java new file mode 100644 index 0000000000..5d0d65e9c5 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/collection/mapkey/MapKeyEnumeratedNonEntityTest.java @@ -0,0 +1,156 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.envers.test.integration.collection.mapkey; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import javax.persistence.CollectionTable; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Id; +import javax.persistence.MapKeyColumn; +import javax.persistence.MapKeyEnumerated; + +import org.hibernate.envers.Audited; +import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase; +import org.hibernate.envers.test.Priority; +import org.hibernate.envers.test.tools.TestTools; +import org.junit.Test; + +import org.hibernate.testing.TestForIssue; + +import static org.hibernate.envers.test.tools.TestTools.checkCollection; +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; + +/** + * @author Chris Cranford + */ +@TestForIssue(jiraKey = "HHH-13655") +public class MapKeyEnumeratedNonEntityTest extends BaseEnversJPAFunctionalTestCase { + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { TestEntity.class }; + } + + @Test + @Priority(10) + public void initData() { + // Revision 1 + doInJPA( this::entityManagerFactory, entityManager -> { + + final TestEntity test = new TestEntity(); + test.setId( 1 ); + test.addMapKeyAssociation( TestEnum.ONE, 1 ); + + entityManager.persist( test ); + } ); + + // Revision 2 + doInJPA( this::entityManagerFactory, entityManager -> { + final TestEntity test = entityManager.find( TestEntity.class, 1 ); + test.addMapKeyAssociation( TestEnum.TWO, 2 ); + + entityManager.merge( test ); + } ); + + // Revision 3 + doInJPA( this::entityManagerFactory, entityManager -> { + final TestEntity test = entityManager.find( TestEntity.class, 1 ); + test.removeMapKeyAssociation( TestEnum.ONE ); + entityManager.merge( test ); + } ); + + // Revision 4 + doInJPA( this::entityManagerFactory, entityManager -> { + final TestEntity test = entityManager.find( TestEntity.class, 1 ); + test.removeMapKeyAssociation( TestEnum.TWO ); + entityManager.merge( test ); + } ); + } + + @Test + public void testRevisionNumberHistory() { + assertEquals( Arrays.asList( 1, 2, 3, 4 ), getAuditReader().getRevisions( TestEntity.class, 1 ) ); + } + + @Test + public void testRevisionHistory() { + + final TestEntity rev1 = getAuditReader().find( TestEntity.class, 1, 1 ); + assertEquals( 1, rev1.getMapEnumMap().size() ); + assertEquals( TestEnum.ONE, rev1.getMapEnumMap().keySet().iterator().next() ); + + final TestEntity rev2 = getAuditReader().find( TestEntity.class, 1, 2 ); + assertEquals( 2, rev2.getMapEnumMap().size() ); + assertEquals( TestTools.makeSet( TestEnum.ONE, TestEnum.TWO ), rev2.getMapEnumMap().keySet() ); + checkCollection( rev2.getMapEnumMap().values(), 1, 2 ); + + final TestEntity rev3 = getAuditReader().find( TestEntity.class, 1, 3 ); + assertEquals( 1, rev3.getMapEnumMap().size() ); + assertEquals( TestTools.makeSet( TestEnum.TWO ), rev3.getMapEnumMap().keySet() ); + checkCollection( rev2.getMapEnumMap().values(), 2 ); + + final TestEntity rev4 = getAuditReader().find( TestEntity.class, 1, 4 ); + assertEquals( 0, rev4.getMapEnumMap().size() ); + } + + public enum TestEnum { + ONE, + TWO + } + + @Entity(name = "TestEntity") + @Audited + public static class TestEntity { + @Id + private Integer id; + + @MapKeyEnumerated(EnumType.STRING) + @ElementCollection + @CollectionTable(name = "test_Entity_enum_items") + @MapKeyColumn(name = "type", length = 20, nullable = false) + private Map mapEnumMap = new HashMap<>(); + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Map getMapEnumMap() { + return mapEnumMap; + } + + public void setMapEnumMap(Map mapEnumMap) { + this.mapEnumMap = mapEnumMap; + } + + @Override + public String toString() { + return "TestEntity{" + + "id=" + id + + ", mapEnumMap=" + mapEnumMap + + '}'; + } + + public void addMapKeyAssociation(TestEnum key, Integer value) { + mapEnumMap.put( key, value ); + } + + public Integer removeMapKeyAssociation(TestEnum key) { + final Integer value = mapEnumMap.get( key ); + mapEnumMap.remove( key ); + return value; + } + } +}