Merge remote-tracking branch 'upstream/master' into wip/6.0
This commit is contained in:
commit
6c3d0d86dc
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
jira:
|
||||||
|
projectKey: "HHH"
|
|
@ -252,7 +252,7 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<XClass> orderAndFillHierarchy(List<XClass> original) {
|
private List<XClass> orderAndFillHierarchy(List<XClass> original) {
|
||||||
List<XClass> copy = new ArrayList<>( original );
|
List<XClass> copy = new ArrayList<>( original.size() );
|
||||||
insertMappedSuperclasses( original, copy );
|
insertMappedSuperclasses( original, copy );
|
||||||
|
|
||||||
// order the hierarchy
|
// order the hierarchy
|
||||||
|
@ -266,16 +266,28 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc
|
||||||
}
|
}
|
||||||
|
|
||||||
private void insertMappedSuperclasses(List<XClass> original, List<XClass> copy) {
|
private void insertMappedSuperclasses(List<XClass> original, List<XClass> copy) {
|
||||||
|
final boolean debug = log.isDebugEnabled();
|
||||||
for ( XClass clazz : original ) {
|
for ( XClass clazz : original ) {
|
||||||
XClass superClass = clazz.getSuperclass();
|
if ( clazz.isAnnotationPresent( javax.persistence.MappedSuperclass.class ) ) {
|
||||||
while ( superClass != null
|
if ( debug ) {
|
||||||
&& !reflectionManager.equals( superClass, Object.class )
|
log.debugf(
|
||||||
&& !copy.contains( superClass ) ) {
|
"Skipping explicit MappedSuperclass %s, the class will be discovered analyzing the implementing class",
|
||||||
if ( superClass.isAnnotationPresent( Entity.class )
|
clazz
|
||||||
|| superClass.isAnnotationPresent( javax.persistence.MappedSuperclass.class ) ) {
|
);
|
||||||
copy.add( superClass );
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
copy.add( clazz );
|
||||||
|
XClass superClass = clazz.getSuperclass();
|
||||||
|
while ( superClass != null
|
||||||
|
&& !reflectionManager.equals( superClass, Object.class )
|
||||||
|
&& !copy.contains( superClass ) ) {
|
||||||
|
if ( superClass.isAnnotationPresent( Entity.class )
|
||||||
|
|| superClass.isAnnotationPresent( javax.persistence.MappedSuperclass.class ) ) {
|
||||||
|
copy.add( superClass );
|
||||||
|
}
|
||||||
|
superClass = superClass.getSuperclass();
|
||||||
}
|
}
|
||||||
superClass = superClass.getSuperclass();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1584,8 +1584,7 @@ public final class AnnotationBinder {
|
||||||
MetadataBuildingContext context) {
|
MetadataBuildingContext context) {
|
||||||
int idPropertyCounter = 0;
|
int idPropertyCounter = 0;
|
||||||
|
|
||||||
Collection<XProperty> properties = propertyContainer.getProperties();
|
for ( XProperty p : propertyContainer.propertyIterator() ) {
|
||||||
for ( XProperty p : properties ) {
|
|
||||||
final int currentIdPropertyCounter = addProperty(
|
final int currentIdPropertyCounter = addProperty(
|
||||||
propertyContainer,
|
propertyContainer,
|
||||||
p,
|
p,
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
package org.hibernate.cfg;
|
package org.hibernate.cfg;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -35,6 +36,7 @@ import org.hibernate.boot.jaxb.SourceType;
|
||||||
import org.hibernate.cfg.annotations.HCANNHelper;
|
import org.hibernate.cfg.annotations.HCANNHelper;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
@ -63,7 +65,7 @@ class PropertyContainer {
|
||||||
*/
|
*/
|
||||||
private final AccessType classLevelAccessType;
|
private final AccessType classLevelAccessType;
|
||||||
|
|
||||||
private final TreeMap<String, XProperty> persistentAttributeMap;
|
private final List<XProperty> persistentAttributes;
|
||||||
|
|
||||||
PropertyContainer(XClass clazz, XClass entityAtStake, AccessType defaultClassLevelAccessType) {
|
PropertyContainer(XClass clazz, XClass entityAtStake, AccessType defaultClassLevelAccessType) {
|
||||||
this.xClass = clazz;
|
this.xClass = clazz;
|
||||||
|
@ -83,7 +85,6 @@ class PropertyContainer {
|
||||||
: defaultClassLevelAccessType;
|
: defaultClassLevelAccessType;
|
||||||
assert classLevelAccessType == AccessType.FIELD || classLevelAccessType == AccessType.PROPERTY;
|
assert classLevelAccessType == AccessType.FIELD || classLevelAccessType == AccessType.PROPERTY;
|
||||||
|
|
||||||
this.persistentAttributeMap = new TreeMap<>();
|
|
||||||
|
|
||||||
final List<XProperty> fields = xClass.getDeclaredProperties( AccessType.FIELD.getType() );
|
final List<XProperty> fields = xClass.getDeclaredProperties( AccessType.FIELD.getType() );
|
||||||
final List<XProperty> getters = xClass.getDeclaredProperties( AccessType.PROPERTY.getType() );
|
final List<XProperty> getters = xClass.getDeclaredProperties( AccessType.PROPERTY.getType() );
|
||||||
|
@ -92,18 +93,23 @@ class PropertyContainer {
|
||||||
|
|
||||||
final Map<String,XProperty> persistentAttributesFromGetters = new HashMap<>();
|
final Map<String,XProperty> persistentAttributesFromGetters = new HashMap<>();
|
||||||
|
|
||||||
|
final TreeMap<String, XProperty> localAttributeMap = new TreeMap<>();
|
||||||
collectPersistentAttributesUsingLocalAccessType(
|
collectPersistentAttributesUsingLocalAccessType(
|
||||||
persistentAttributeMap,
|
xClass,
|
||||||
|
localAttributeMap,
|
||||||
persistentAttributesFromGetters,
|
persistentAttributesFromGetters,
|
||||||
fields,
|
fields,
|
||||||
getters
|
getters
|
||||||
);
|
);
|
||||||
collectPersistentAttributesUsingClassLevelAccessType(
|
collectPersistentAttributesUsingClassLevelAccessType(
|
||||||
persistentAttributeMap,
|
xClass,
|
||||||
|
classLevelAccessType,
|
||||||
|
localAttributeMap,
|
||||||
persistentAttributesFromGetters,
|
persistentAttributesFromGetters,
|
||||||
fields,
|
fields,
|
||||||
getters
|
getters
|
||||||
);
|
);
|
||||||
|
this.persistentAttributes = verifyAndInitializePersistentAttributes( xClass, localAttributeMap );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void preFilter(List<XProperty> fields, List<XProperty> getters) {
|
private void preFilter(List<XProperty> fields, List<XProperty> getters) {
|
||||||
|
@ -124,7 +130,8 @@ class PropertyContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void collectPersistentAttributesUsingLocalAccessType(
|
private static void collectPersistentAttributesUsingLocalAccessType(
|
||||||
|
XClass xClass,
|
||||||
TreeMap<String, XProperty> persistentAttributeMap,
|
TreeMap<String, XProperty> persistentAttributeMap,
|
||||||
Map<String,XProperty> persistentAttributesFromGetters,
|
Map<String,XProperty> persistentAttributesFromGetters,
|
||||||
List<XProperty> fields,
|
List<XProperty> fields,
|
||||||
|
@ -176,7 +183,9 @@ class PropertyContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void collectPersistentAttributesUsingClassLevelAccessType(
|
private static void collectPersistentAttributesUsingClassLevelAccessType(
|
||||||
|
XClass xClass,
|
||||||
|
AccessType classLevelAccessType,
|
||||||
TreeMap<String, XProperty> persistentAttributeMap,
|
TreeMap<String, XProperty> persistentAttributeMap,
|
||||||
Map<String,XProperty> persistentAttributesFromGetters,
|
Map<String,XProperty> persistentAttributesFromGetters,
|
||||||
List<XProperty> fields,
|
List<XProperty> fields,
|
||||||
|
@ -229,20 +238,30 @@ class PropertyContainer {
|
||||||
return classLevelAccessType;
|
return classLevelAccessType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use the {@link #propertyIterator()} method instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public Collection<XProperty> getProperties() {
|
public Collection<XProperty> getProperties() {
|
||||||
assertTypesAreResolvable();
|
return Collections.unmodifiableCollection( this.persistentAttributes );
|
||||||
return Collections.unmodifiableCollection( persistentAttributeMap.values() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertTypesAreResolvable() {
|
public Iterable<XProperty> propertyIterator() {
|
||||||
for ( XProperty xProperty : persistentAttributeMap.values() ) {
|
return persistentAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<XProperty> verifyAndInitializePersistentAttributes(XClass xClass, Map<String, XProperty> localAttributeMap) {
|
||||||
|
ArrayList<XProperty> output = new ArrayList( localAttributeMap.size() );
|
||||||
|
for ( XProperty xProperty : localAttributeMap.values() ) {
|
||||||
if ( !xProperty.isTypeResolved() && !discoverTypeWithoutReflection( xProperty ) ) {
|
if ( !xProperty.isTypeResolved() && !discoverTypeWithoutReflection( xProperty ) ) {
|
||||||
String msg = "Property " + StringHelper.qualify( xClass.getName(), xProperty.getName() ) +
|
String msg = "Property " + StringHelper.qualify( xClass.getName(), xProperty.getName() ) +
|
||||||
" has an unbound type and no explicit target entity. Resolve this Generic usage issue" +
|
" has an unbound type and no explicit target entity. Resolve this Generic usage issue" +
|
||||||
" or set an explicit target attribute (eg @OneToMany(target=) or use an explicit @Type";
|
" or set an explicit target attribute (eg @OneToMany(target=) or use an explicit @Type";
|
||||||
throw new AnnotationException( msg );
|
throw new AnnotationException( msg );
|
||||||
}
|
}
|
||||||
|
output.add( xProperty );
|
||||||
}
|
}
|
||||||
|
return CollectionHelper.toSmallList( output );
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// private void considerExplicitFieldAndPropertyAccess() {
|
// private void considerExplicitFieldAndPropertyAccess() {
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* 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.mapping;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Objects;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.IdClass;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@TestForIssue(jiraKey = "HHH-14499")
|
||||||
|
public class MappedSuperclassWithGenericsTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {
|
||||||
|
IntermediateAbstractMapped.class,
|
||||||
|
BaseEntity.class,
|
||||||
|
AbstractGenericMappedSuperType.class,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIt() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
public static abstract class AbstractGenericMappedSuperType<T> {
|
||||||
|
|
||||||
|
private T whateverType;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
@IdClass(PK.class)
|
||||||
|
public static abstract class IntermediateAbstractMapped<T> extends AbstractGenericMappedSuperType<T> {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String keyOne;
|
||||||
|
@Id
|
||||||
|
private String keyTwo;
|
||||||
|
@Id
|
||||||
|
private String keyThree;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
|
public static class PK implements Serializable {
|
||||||
|
|
||||||
|
private String keyOne;
|
||||||
|
private String keyTwo;
|
||||||
|
private String keyThree;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if ( this == o ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ( o == null || getClass() != o.getClass() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PK pk = (PK) o;
|
||||||
|
return Objects.equals( keyOne, pk.keyOne ) &&
|
||||||
|
Objects.equals( keyTwo, pk.keyTwo ) &&
|
||||||
|
Objects.equals( keyThree, pk.keyThree );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash( keyOne, keyTwo, keyThree );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "BaseEntity")
|
||||||
|
public static class BaseEntity<T> extends IntermediateAbstractMapped<byte[]> {
|
||||||
|
|
||||||
|
String aString;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue