HHH-12124 - The JPA Metamodel does not allow to retrieve the actual EmbeddableType since all instances are registered by the associated Java type
This commit is contained in:
parent
84439af053
commit
e6ea4828db
|
@ -57,7 +57,7 @@ class MetadataContext {
|
||||||
private Map<Class<?>, EntityTypeImpl<?>> entityTypes = new HashMap<>();
|
private Map<Class<?>, EntityTypeImpl<?>> entityTypes = new HashMap<>();
|
||||||
private Map<String, EntityTypeImpl<?>> entityTypesByEntityName = new HashMap<>();
|
private Map<String, EntityTypeImpl<?>> entityTypesByEntityName = new HashMap<>();
|
||||||
private Map<PersistentClass, EntityTypeImpl<?>> entityTypesByPersistentClass = new HashMap<>();
|
private Map<PersistentClass, EntityTypeImpl<?>> entityTypesByPersistentClass = new HashMap<>();
|
||||||
private Map<Class<?>, EmbeddableTypeImpl<?>> embeddables = new HashMap<>();
|
private Set<EmbeddableTypeImpl<?>> embeddables = new HashSet<>();
|
||||||
private Map<MappedSuperclass, MappedSuperclassTypeImpl<?>> mappedSuperclassByMappedSuperclassMapping = new HashMap<>();
|
private Map<MappedSuperclass, MappedSuperclassTypeImpl<?>> mappedSuperclassByMappedSuperclassMapping = new HashMap<>();
|
||||||
//this list contains MappedSuperclass and EntityTypes ordered by superclass first
|
//this list contains MappedSuperclass and EntityTypes ordered by superclass first
|
||||||
private List<Object> orderedMappings = new ArrayList<>();
|
private List<Object> orderedMappings = new ArrayList<>();
|
||||||
|
@ -93,8 +93,8 @@ class MetadataContext {
|
||||||
return Collections.unmodifiableMap( entityTypes );
|
return Collections.unmodifiableMap( entityTypes );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Class<?>, EmbeddableTypeImpl<?>> getEmbeddableTypeMap() {
|
public Set<EmbeddableTypeImpl<?>> getEmbeddableTypeMap() {
|
||||||
return Collections.unmodifiableMap( embeddables );
|
return Collections.unmodifiableSet( embeddables );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Class<?>, MappedSuperclassType<?>> getMappedSuperclassTypeMap() {
|
public Map<Class<?>, MappedSuperclassType<?>> getMappedSuperclassTypeMap() {
|
||||||
|
@ -123,7 +123,7 @@ class MetadataContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*package*/ void registerEmbeddedableType(EmbeddableTypeImpl<?> embeddableType) {
|
/*package*/ void registerEmbeddedableType(EmbeddableTypeImpl<?> embeddableType) {
|
||||||
embeddables.put( embeddableType.getJavaType(), embeddableType );
|
embeddables.add( embeddableType );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*package*/ void registerMappedSuperclassType(
|
/*package*/ void registerMappedSuperclassType(
|
||||||
|
@ -268,7 +268,7 @@ class MetadataContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( staticMetamodelScanEnabled ) {
|
if ( staticMetamodelScanEnabled ) {
|
||||||
for ( EmbeddableTypeImpl embeddable : embeddables.values() ) {
|
for ( EmbeddableTypeImpl embeddable : embeddables ) {
|
||||||
populateStaticMetamodel( embeddable );
|
populateStaticMetamodel( embeddable );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import javax.persistence.EntityGraph;
|
import javax.persistence.EntityGraph;
|
||||||
import javax.persistence.NamedAttributeNode;
|
import javax.persistence.NamedAttributeNode;
|
||||||
import javax.persistence.NamedEntityGraph;
|
import javax.persistence.NamedEntityGraph;
|
||||||
|
@ -90,6 +91,18 @@ public class MetamodelImpl implements MetamodelImplementor, Serializable {
|
||||||
|
|
||||||
|
|
||||||
private final Map<Class<?>, EntityTypeImpl<?>> jpaEntityTypeMap = new ConcurrentHashMap<>();
|
private final Map<Class<?>, EntityTypeImpl<?>> jpaEntityTypeMap = new ConcurrentHashMap<>();
|
||||||
|
/**
|
||||||
|
* There can be multiple instances of an Embeddable type, each one being relative to its parent entity.
|
||||||
|
*/
|
||||||
|
private final Set<EmbeddableTypeImpl<?>> jpaEmbeddableTypes = new CopyOnWriteArraySet<>();
|
||||||
|
/**
|
||||||
|
* That's not strictly correct in the JPA standard since for a given Java type we could have
|
||||||
|
* multiple instances of an embeddable type. Some embeddable might override attributes, but we
|
||||||
|
* can only return a single EmbeddableTypeImpl for a given Java object class.
|
||||||
|
*
|
||||||
|
* A better approach would be if the parent class and attribute name would be included as well
|
||||||
|
* when trying to locate the embeddable type.
|
||||||
|
*/
|
||||||
private final Map<Class<?>, EmbeddableTypeImpl<?>> jpaEmbeddableTypeMap = new ConcurrentHashMap<>();
|
private final Map<Class<?>, EmbeddableTypeImpl<?>> jpaEmbeddableTypeMap = new ConcurrentHashMap<>();
|
||||||
private final Map<Class<?>, MappedSuperclassType<?>> jpaMappedSuperclassTypeMap = new ConcurrentHashMap<>();
|
private final Map<Class<?>, MappedSuperclassType<?>> jpaMappedSuperclassTypeMap = new ConcurrentHashMap<>();
|
||||||
private final Map<String, EntityTypeImpl<?>> jpaEntityTypesByEntityName = new ConcurrentHashMap<>();
|
private final Map<String, EntityTypeImpl<?>> jpaEntityTypesByEntityName = new ConcurrentHashMap<>();
|
||||||
|
@ -230,7 +243,10 @@ public class MetamodelImpl implements MetamodelImplementor, Serializable {
|
||||||
context.wrapUp();
|
context.wrapUp();
|
||||||
|
|
||||||
this.jpaEntityTypeMap.putAll( context.getEntityTypeMap() );
|
this.jpaEntityTypeMap.putAll( context.getEntityTypeMap() );
|
||||||
this.jpaEmbeddableTypeMap.putAll( context.getEmbeddableTypeMap() );
|
this.jpaEmbeddableTypes.addAll( context.getEmbeddableTypeMap() );
|
||||||
|
for ( EmbeddableTypeImpl<?> embeddable: jpaEmbeddableTypes ) {
|
||||||
|
this.jpaEmbeddableTypeMap.put( embeddable.getJavaType(), embeddable );
|
||||||
|
}
|
||||||
this.jpaMappedSuperclassTypeMap.putAll( context.getMappedSuperclassTypeMap() );
|
this.jpaMappedSuperclassTypeMap.putAll( context.getMappedSuperclassTypeMap() );
|
||||||
this.jpaEntityTypesByEntityName.putAll( context.getEntityTypesByEntityName() );
|
this.jpaEntityTypesByEntityName.putAll( context.getEntityTypesByEntityName() );
|
||||||
|
|
||||||
|
@ -547,12 +563,12 @@ public class MetamodelImpl implements MetamodelImplementor, Serializable {
|
||||||
@Override
|
@Override
|
||||||
public Set<ManagedType<?>> getManagedTypes() {
|
public Set<ManagedType<?>> getManagedTypes() {
|
||||||
final int setSize = CollectionHelper.determineProperSizing(
|
final int setSize = CollectionHelper.determineProperSizing(
|
||||||
jpaEntityTypeMap.size() + jpaMappedSuperclassTypeMap.size() + jpaEmbeddableTypeMap.size()
|
jpaEntityTypeMap.size() + jpaMappedSuperclassTypeMap.size() + jpaEmbeddableTypes.size()
|
||||||
);
|
);
|
||||||
final Set<ManagedType<?>> managedTypes = new HashSet<ManagedType<?>>( setSize );
|
final Set<ManagedType<?>> managedTypes = new HashSet<ManagedType<?>>( setSize );
|
||||||
managedTypes.addAll( jpaEntityTypeMap.values() );
|
managedTypes.addAll( jpaEntityTypeMap.values() );
|
||||||
managedTypes.addAll( jpaMappedSuperclassTypeMap.values() );
|
managedTypes.addAll( jpaMappedSuperclassTypeMap.values() );
|
||||||
managedTypes.addAll( jpaEmbeddableTypeMap.values() );
|
managedTypes.addAll( jpaEmbeddableTypes );
|
||||||
return managedTypes;
|
return managedTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,7 +579,7 @@ public class MetamodelImpl implements MetamodelImplementor, Serializable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<EmbeddableType<?>> getEmbeddables() {
|
public Set<EmbeddableType<?>> getEmbeddables() {
|
||||||
return new HashSet<>( jpaEmbeddableTypeMap.values() );
|
return new HashSet<>( jpaEmbeddableTypes );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.metamodel;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public class Address implements Serializable {
|
||||||
|
|
||||||
|
private String city;
|
||||||
|
|
||||||
|
private String street;
|
||||||
|
|
||||||
|
public String getCity() {
|
||||||
|
return city;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCity(String city) {
|
||||||
|
this.city = city;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStreet() {
|
||||||
|
return street;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStreet(String street) {
|
||||||
|
this.street = street;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.metamodel;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Embedded;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Company implements Serializable {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private long id = System.nanoTime();
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private Address address = new Address();
|
||||||
|
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(Address address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,30 +6,45 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.metamodel;
|
package org.hibernate.test.metamodel;
|
||||||
|
|
||||||
|
import javax.persistence.metamodel.Type;
|
||||||
|
|
||||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class EmbeddableMetaModelTest extends BaseEntityManagerFunctionalTestCase {
|
public class EmbeddableMetaModelTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
@Override
|
@Override
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
return new Class[]{
|
return new Class[] {
|
||||||
ProductEntity.class
|
ProductEntity.class,
|
||||||
};
|
Person.class,
|
||||||
}
|
Company.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-11111")
|
@TestForIssue(jiraKey = "HHH-11111")
|
||||||
public void testEmbeddableCanBeResolvedWhenUsedAsInterface() {
|
public void testEmbeddableCanBeResolvedWhenUsedAsInterface() {
|
||||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
assertNotNull(entityManager.getMetamodel().embeddable(LocalizedValue.class));
|
assertNotNull( entityManager.getMetamodel().embeddable( LocalizedValue.class ) );
|
||||||
assertEquals( LocalizedValue.class, ProductEntity_.description.getElementType().getJavaType() );
|
assertEquals( LocalizedValue.class, ProductEntity_.description.getElementType().getJavaType() );
|
||||||
assertNotNull( LocalizedValue_.value );
|
assertNotNull( LocalizedValue_.value );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-12124")
|
||||||
|
public void testEmbeddableEquality() {
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
assertTrue( entityManager.getMetamodel().getEmbeddables().contains( Company_.address.getType() ) );
|
||||||
|
assertTrue( entityManager.getMetamodel().getEmbeddables().contains( Person_.address.getType() ) );
|
||||||
|
} );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.metamodel;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Embedded;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Person implements Serializable {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private long id = System.nanoTime();
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private Address address = new Address();
|
||||||
|
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(Address address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue