HHH-6148 Adding classmate as a replacement for the commons annotations generic resolution code
This commit is contained in:
parent
8f01c1c200
commit
dd019a1f43
|
@ -51,6 +51,7 @@ libraries = [
|
|||
commons_annotations:
|
||||
'org.hibernate:hibernate-commons-annotations:3.2.0.Final',
|
||||
jandex: 'org.jboss:jandex:1.0.0.Beta6',
|
||||
classmate: 'com.fasterxml:classmate:0.5.2',
|
||||
|
||||
// Jakarta commons-collections todo : get rid of commons-collections dependency
|
||||
commons_collections:
|
||||
|
|
|
@ -10,6 +10,7 @@ dependencies {
|
|||
}
|
||||
compile( libraries.commons_annotations )
|
||||
compile( libraries.jandex )
|
||||
compile( libraries.classmate )
|
||||
compile( libraries.jpa )
|
||||
compile( libraries.javassist )
|
||||
antlr( libraries.antlr )
|
||||
|
|
|
@ -26,6 +26,7 @@ package org.hibernate.metamodel.source.annotations;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
@ -33,6 +34,9 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import javax.persistence.AccessType;
|
||||
|
||||
import com.fasterxml.classmate.ResolvedTypeWithMembers;
|
||||
import com.fasterxml.classmate.members.HierarchicType;
|
||||
import com.fasterxml.classmate.members.ResolvedMember;
|
||||
import org.jboss.jandex.AnnotationInstance;
|
||||
import org.jboss.jandex.AnnotationTarget;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
|
@ -40,6 +44,7 @@ import org.jboss.jandex.FieldInfo;
|
|||
import org.jboss.jandex.MethodInfo;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.metamodel.source.annotations.util.JandexHelper;
|
||||
import org.hibernate.metamodel.source.annotations.util.ReflectionHelper;
|
||||
|
@ -61,20 +66,22 @@ public class ConfiguredClass {
|
|||
private final boolean isMappedSuperClass;
|
||||
private final List<MappedProperty> mappedProperties;
|
||||
|
||||
public ConfiguredClass(ClassInfo info, ConfiguredClass parent, AccessType hierarchyAccessType, ServiceRegistry serviceRegistry) {
|
||||
public ConfiguredClass(ClassInfo info, ConfiguredClass parent, AccessType hierarchyAccessType, ServiceRegistry serviceRegistry, ResolvedTypeWithMembers resolvedType) {
|
||||
this.classInfo = info;
|
||||
this.parent = parent;
|
||||
this.isRoot = parent == null;
|
||||
this.hierarchyAccessType = hierarchyAccessType;
|
||||
|
||||
AnnotationInstance mappedSuperClassAnnotation = assertNotEntityAndMAppedSuperClass();
|
||||
AnnotationInstance mappedSuperClassAnnotation = assertNotEntityAndMappedSuperClass();
|
||||
|
||||
this.clazz = serviceRegistry.getService( ClassLoaderService.class ).classForName( info.toString() );
|
||||
isMappedSuperClass = mappedSuperClassAnnotation != null;
|
||||
classAccessType = determineClassAccessType();
|
||||
mappedProperties = collectMappedProperties();
|
||||
|
||||
List<MappedProperty> tmpProperties = collectMappedProperties( resolvedType );
|
||||
// make sure the properties are ordered by property name
|
||||
Collections.sort( mappedProperties );
|
||||
Collections.sort( tmpProperties );
|
||||
mappedProperties = Collections.unmodifiableList( tmpProperties );
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
@ -97,11 +104,18 @@ public class ConfiguredClass {
|
|||
return isMappedSuperClass;
|
||||
}
|
||||
|
||||
public List<MappedProperty> getMappedProperties() {
|
||||
return mappedProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append( "ConfiguredClass" );
|
||||
sb.append( "{classInfo=" ).append( classInfo );
|
||||
sb.append( "{clazz=" ).append( clazz );
|
||||
sb.append( ", mappedProperties=" ).append( mappedProperties );
|
||||
sb.append( ", classAccessType=" ).append( classAccessType );
|
||||
sb.append( ", isRoot=" ).append( isRoot );
|
||||
sb.append( '}' );
|
||||
return sb.toString();
|
||||
}
|
||||
|
@ -118,41 +132,78 @@ public class ConfiguredClass {
|
|||
return accessType;
|
||||
}
|
||||
|
||||
private List<MappedProperty> collectMappedProperties() {
|
||||
/**
|
||||
* @return A list of the persistent properties of this configured class
|
||||
*/
|
||||
private List<MappedProperty> collectMappedProperties(ResolvedTypeWithMembers resolvedTypes) {
|
||||
// create sets of transient field and method names
|
||||
Set<String> transientFieldNames = new HashSet<String>();
|
||||
Set<String> transientMethodNames = new HashSet<String>();
|
||||
populateTransientFieldAndMethodLists( transientFieldNames, transientMethodNames );
|
||||
|
||||
List<Member> classMembers = new ArrayList<Member>();
|
||||
Set<String> explicitlyConfiguredAccessMemberNames;
|
||||
// use the class mate library to generic types
|
||||
ResolvedTypeWithMembers resolvedType = null;
|
||||
for ( HierarchicType hierarchicType : resolvedTypes.allTypesAndOverrides() ) {
|
||||
if ( hierarchicType.getType().getErasedType().equals( clazz ) ) {
|
||||
resolvedType = ReflectionHelper.resolveMemberTypes( hierarchicType.getType() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( resolvedType == null ) {
|
||||
throw new AssertionFailure( "Unable to resolve types for " + clazz.getName() );
|
||||
}
|
||||
|
||||
List<MappedProperty> properties = new ArrayList<MappedProperty>();
|
||||
Set<String> explicitlyConfiguredMemberNames = createExplicitlyConfiguredAccessProperties(
|
||||
properties, resolvedType
|
||||
);
|
||||
|
||||
if ( AccessType.FIELD.equals( classAccessType ) ) {
|
||||
explicitlyConfiguredAccessMemberNames = addExplicitAccessMembers( classMembers, MethodInfo.class );
|
||||
Field fields[] = clazz.getDeclaredFields();
|
||||
Field.setAccessible( fields, true );
|
||||
for ( Field field : fields ) {
|
||||
if ( !transientFieldNames.contains( field.getName() )
|
||||
&& !explicitlyConfiguredAccessMemberNames.contains( field.getName() ) ) {
|
||||
classMembers.add( field );
|
||||
if ( isPersistentMember( transientFieldNames, explicitlyConfiguredMemberNames, field ) ) {
|
||||
properties.add( createMappedProperty( field, resolvedType ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
explicitlyConfiguredAccessMemberNames = addExplicitAccessMembers( classMembers, FieldInfo.class );
|
||||
Method[] methods = clazz.getDeclaredMethods();
|
||||
Method.setAccessible( methods, true );
|
||||
for ( Method method : methods ) {
|
||||
if ( !transientMethodNames.contains( method.getName() )
|
||||
&& !explicitlyConfiguredAccessMemberNames.contains( ReflectionHelper.getPropertyName( method ) ) ) {
|
||||
classMembers.add( method );
|
||||
if ( isPersistentMember( transientMethodNames, explicitlyConfiguredMemberNames, method ) ) {
|
||||
properties.add( createMappedProperty( method, resolvedType ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<MappedProperty> properties = new ArrayList<MappedProperty>();
|
||||
return properties;
|
||||
}
|
||||
|
||||
private Set<String> addExplicitAccessMembers(List<Member> classMembers, Class<? extends AnnotationTarget> targetClass) {
|
||||
private boolean isPersistentMember(Set<String> transientNames, Set<String> explicitlyConfiguredMemberNames, Member member) {
|
||||
if ( !ReflectionHelper.isProperty( member ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( transientNames.contains( member.getName() ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( explicitlyConfiguredMemberNames.contains( member.getName() ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@code MappedProperty} instances for the explicitly configured persistent properties
|
||||
*
|
||||
* @param mappedProperties list to which to add the explicitly configured mapped properties
|
||||
*
|
||||
* @return the property names of the explicitly configured class names in a set
|
||||
*/
|
||||
private Set<String> createExplicitlyConfiguredAccessProperties(List<MappedProperty> mappedProperties, ResolvedTypeWithMembers resolvedMembers) {
|
||||
Set<String> explicitAccessMembers = new HashSet<String>();
|
||||
|
||||
List<AnnotationInstance> accessAnnotations = classInfo.annotations().get( JPADotNames.ACCESS );
|
||||
|
@ -160,60 +211,106 @@ public class ConfiguredClass {
|
|||
return explicitAccessMembers;
|
||||
}
|
||||
|
||||
// iterate over all @Access annotations defined on the current class
|
||||
for ( AnnotationInstance accessAnnotation : accessAnnotations ) {
|
||||
// at this stage we are only interested at annotations defined on fields and methods
|
||||
AnnotationTarget target = accessAnnotation.target();
|
||||
if ( !target.getClass().equals( targetClass ) ) {
|
||||
// we are only interested at annotations defined on fields and methods
|
||||
AnnotationTarget annotationTarget = accessAnnotation.target();
|
||||
if ( !( annotationTarget.getClass().equals( MethodInfo.class ) || annotationTarget.getClass()
|
||||
.equals( FieldInfo.class ) ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AccessType accessType = Enum.valueOf( AccessType.class, accessAnnotation.value().asEnum() );
|
||||
|
||||
if ( target instanceof MethodInfo && MethodInfo.class.equals( targetClass ) ) {
|
||||
// annotating a field with @AccessType(PROPERTY) has not effect
|
||||
if ( !AccessType.PROPERTY.equals( accessType ) ) {
|
||||
// when class access type is field
|
||||
// overriding access annotations must be placed on properties and have the access type PROPERTY
|
||||
if ( AccessType.FIELD.equals( classAccessType ) ) {
|
||||
if ( !( annotationTarget instanceof MethodInfo ) ) {
|
||||
// todo log warning !?
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !AccessType.PROPERTY.equals( accessType ) ) {
|
||||
// todo log warning !?
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// when class access type is property
|
||||
// overriding access annotations must be placed on fields and have the access type FIELD
|
||||
if ( AccessType.PROPERTY.equals( classAccessType ) ) {
|
||||
if ( !( annotationTarget instanceof FieldInfo ) ) {
|
||||
// todo log warning !?
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !AccessType.FIELD.equals( accessType ) ) {
|
||||
// todo log warning !?
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// the placement is correct, get the member
|
||||
Member member;
|
||||
if ( annotationTarget instanceof MethodInfo ) {
|
||||
Method m;
|
||||
try {
|
||||
m = clazz.getMethod( ( (MethodInfo) target ).name() );
|
||||
m = clazz.getMethod( ( (MethodInfo) annotationTarget ).name() );
|
||||
}
|
||||
catch ( NoSuchMethodException e ) {
|
||||
throw new HibernateException(
|
||||
"Unable to load method "
|
||||
+ ( (MethodInfo) target ).name()
|
||||
+ ( (MethodInfo) annotationTarget ).name()
|
||||
+ " of class " + clazz.getName()
|
||||
);
|
||||
}
|
||||
classMembers.add( m );
|
||||
explicitAccessMembers.add( ReflectionHelper.getPropertyName( m ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( target instanceof FieldInfo && FieldInfo.class.equals( targetClass ) ) {
|
||||
// annotating a method w/ @AccessType(FIELD) has no effect
|
||||
if ( !AccessType.FIELD.equals( accessType ) ) {
|
||||
continue;
|
||||
member = m;
|
||||
}
|
||||
else {
|
||||
Field f;
|
||||
try {
|
||||
f = clazz.getField( ( (FieldInfo) target ).name() );
|
||||
f = clazz.getField( ( (FieldInfo) annotationTarget ).name() );
|
||||
}
|
||||
catch ( NoSuchFieldException e ) {
|
||||
throw new HibernateException(
|
||||
"Unable to load field "
|
||||
+ ( (FieldInfo) target ).name()
|
||||
+ ( (FieldInfo) annotationTarget ).name()
|
||||
+ " of class " + clazz.getName()
|
||||
);
|
||||
}
|
||||
classMembers.add( f );
|
||||
explicitAccessMembers.add( f.getName() );
|
||||
continue;
|
||||
member = f;
|
||||
}
|
||||
if ( ReflectionHelper.isProperty( member ) ) {
|
||||
mappedProperties.add( createMappedProperty( member, resolvedMembers ) );
|
||||
explicitAccessMembers.add( member.getName() );
|
||||
}
|
||||
}
|
||||
return explicitAccessMembers;
|
||||
}
|
||||
|
||||
private MappedProperty createMappedProperty(Member member, ResolvedTypeWithMembers resolvedType) {
|
||||
String name = ReflectionHelper.getPropertyName( member );
|
||||
ResolvedMember[] resolvedMembers;
|
||||
if ( member instanceof Field ) {
|
||||
resolvedMembers = resolvedType.getMemberFields();
|
||||
}
|
||||
else {
|
||||
resolvedMembers = resolvedType.getMemberMethods();
|
||||
}
|
||||
Type type = findResolvedType( member.getName(), resolvedMembers );
|
||||
return new MappedProperty( name, type );
|
||||
}
|
||||
|
||||
private Type findResolvedType(String name, ResolvedMember[] resolvedMembers) {
|
||||
for ( ResolvedMember resolvedMember : resolvedMembers ) {
|
||||
if ( resolvedMember.getName().equals( name ) ) {
|
||||
return resolvedMember.getType().getErasedType();
|
||||
}
|
||||
}
|
||||
// todo - what to do here
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the sets of transient field and method names.
|
||||
*
|
||||
|
@ -237,7 +334,7 @@ public class ConfiguredClass {
|
|||
}
|
||||
}
|
||||
|
||||
private AnnotationInstance assertNotEntityAndMAppedSuperClass() {
|
||||
private AnnotationInstance assertNotEntityAndMappedSuperClass() {
|
||||
//@Entity and @MappedSuperclass on the same class leads to a NPE down the road
|
||||
AnnotationInstance jpaEntityAnnotation = JandexHelper.getSingleAnnotation( classInfo, JPADotNames.ENTITY );
|
||||
AnnotationInstance mappedSuperClassAnnotation = JandexHelper.getSingleAnnotation(
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.util.List;
|
|||
import javax.persistence.AccessType;
|
||||
import javax.persistence.InheritanceType;
|
||||
|
||||
import com.fasterxml.classmate.ResolvedTypeWithMembers;
|
||||
import org.jboss.jandex.AnnotationInstance;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.FieldInfo;
|
||||
|
@ -36,7 +37,9 @@ import org.jboss.jandex.MethodInfo;
|
|||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.metamodel.source.annotations.util.JandexHelper;
|
||||
import org.hibernate.metamodel.source.annotations.util.ReflectionHelper;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.service.classloading.spi.ClassLoaderService;
|
||||
|
||||
/**
|
||||
* Represents the inheritance structure of the configured classes within a class hierarchy.
|
||||
|
@ -56,10 +59,14 @@ public class ConfiguredClassHierarchy implements Iterable<ConfiguredClass> {
|
|||
defaultAccessType = determineDefaultAccessType( classes );
|
||||
inheritanceType = determineInheritanceType( classes );
|
||||
|
||||
ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
|
||||
Class<?> clazz = classLoaderService.classForName( classes.get( classes.size() - 1 ).name().toString() );
|
||||
ResolvedTypeWithMembers resolvedMembers = ReflectionHelper.resolveMemberTypes( clazz );
|
||||
|
||||
configuredClasses = new ArrayList<ConfiguredClass>();
|
||||
ConfiguredClass parent = null;
|
||||
for ( ClassInfo info : classes ) {
|
||||
ConfiguredClass configuredClass = new ConfiguredClass( info, parent, defaultAccessType, serviceRegistry );
|
||||
ConfiguredClass configuredClass = new ConfiguredClass( info, parent, defaultAccessType, serviceRegistry, resolvedMembers );
|
||||
configuredClasses.add( configuredClass );
|
||||
parent = configuredClass;
|
||||
}
|
||||
|
@ -81,8 +88,7 @@ public class ConfiguredClassHierarchy implements Iterable<ConfiguredClass> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String toString
|
||||
() {
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append( "ConfiguredClassHierarchy" );
|
||||
sb.append( "{defaultAccessType=" ).append( defaultAccessType );
|
||||
|
|
|
@ -27,15 +27,11 @@ import java.util.LinkedHashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.GeneratedValue;
|
||||
|
||||
import org.jboss.jandex.AnnotationInstance;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.cfg.BinderHelper;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.mapping.MetaAttribute;
|
||||
import org.hibernate.mapping.PropertyGeneration;
|
||||
import org.hibernate.metamodel.binding.EntityBinding;
|
||||
import org.hibernate.metamodel.binding.HibernateTypeDescriptor;
|
||||
|
@ -110,7 +106,11 @@ public class EntityBinder {
|
|||
entityBinding.getEntity().getOrCreateSingularAttribute( idName );
|
||||
SimpleAttributeBinding idBinding = entityBinding.makeSimplePrimaryKeyAttributeBinding( idName );
|
||||
|
||||
idBinding.initialize( new AnnotationSimpleAttributeDomainState() );
|
||||
|
||||
AnnotationSimpleAttributeDomainState domainState = new AnnotationSimpleAttributeDomainState();
|
||||
//domainState.propertyGeneration =
|
||||
|
||||
idBinding.initialize( domainState );
|
||||
idBinding.initializeTupleValue( new AnnotationSimpleAttributeRelationalState() );
|
||||
}
|
||||
|
||||
|
@ -198,6 +198,8 @@ public class EntityBinder {
|
|||
}
|
||||
|
||||
public static class AnnotationSimpleAttributeDomainState implements SimpleAttributeBinding.DomainState {
|
||||
PropertyGeneration propertyGeneration;
|
||||
|
||||
@Override
|
||||
public PropertyGeneration getPropertyGeneration() {
|
||||
|
||||
|
@ -208,7 +210,7 @@ public class EntityBinder {
|
|||
// String generatorName = generatedValue != null ?
|
||||
// generatedValue.generator() :
|
||||
// BinderHelper.ANNOTATION_STRING_DEFAULT;
|
||||
return PropertyGeneration.ALWAYS;
|
||||
return propertyGeneration;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -272,7 +274,7 @@ public class EntityBinder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, MetaAttribute> getMetaAttributes(EntityBinding entityBinding) {
|
||||
public Map<String, org.hibernate.metamodel.domain.MetaAttribute> getMetaAttributes(EntityBinding entityBinding) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.source.annotations;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Represent a mapped property (explicitly or implicitly mapped).
|
||||
*
|
||||
|
@ -30,19 +32,35 @@ package org.hibernate.metamodel.source.annotations;
|
|||
*/
|
||||
public class MappedProperty implements Comparable<MappedProperty> {
|
||||
private final String name;
|
||||
private final Type type;
|
||||
|
||||
MappedProperty(String name) {
|
||||
MappedProperty(String name, Type type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(MappedProperty mappedProperty) {
|
||||
return name.compareTo( mappedProperty.getName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append( "MappedProperty" );
|
||||
sb.append( "{name='" ).append( name ).append( '\'' );
|
||||
sb.append( ", type=" ).append( type );
|
||||
sb.append( '}' );
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,12 @@ import java.beans.Introspector;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import com.fasterxml.classmate.MemberResolver;
|
||||
import com.fasterxml.classmate.ResolvedType;
|
||||
import com.fasterxml.classmate.ResolvedTypeWithMembers;
|
||||
import com.fasterxml.classmate.TypeResolver;
|
||||
|
||||
/**
|
||||
* Some helper methods for reflection tasks
|
||||
|
@ -11,6 +17,8 @@ import java.lang.reflect.Method;
|
|||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public class ReflectionHelper {
|
||||
private static final TypeResolver typeResolver = new TypeResolver();
|
||||
|
||||
private ReflectionHelper() {
|
||||
}
|
||||
|
||||
|
@ -19,7 +27,7 @@ public class ReflectionHelper {
|
|||
*
|
||||
* @param member the member for which to get the property name.
|
||||
*
|
||||
* @return The bean method name with the "is" or "get" prefix stripped off, <code>null</code>
|
||||
* @return The bean method name with the "is" or "get" prefix stripped off, {@code null}
|
||||
* the method name id not according to the JavaBeans standard.
|
||||
*/
|
||||
public static String getPropertyName(Member member) {
|
||||
|
@ -43,6 +51,31 @@ public class ReflectionHelper {
|
|||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public static ResolvedTypeWithMembers resolveMemberTypes(Class<?> clazz) {
|
||||
ResolvedType resolvedType = typeResolver.resolve( clazz );
|
||||
MemberResolver memberResolver = new MemberResolver( typeResolver );
|
||||
return memberResolver.resolve( resolvedType, null, null );
|
||||
}
|
||||
|
||||
public static ResolvedTypeWithMembers resolveMemberTypes(ResolvedType type) {
|
||||
MemberResolver memberResolver = new MemberResolver( typeResolver );
|
||||
return memberResolver.resolve( type, null, null );
|
||||
}
|
||||
|
||||
public static boolean isProperty(Member m) {
|
||||
if ( m instanceof Method ) {
|
||||
Method method = (Method) m;
|
||||
return !method.isSynthetic()
|
||||
&& !method.isBridge()
|
||||
&& !Modifier.isStatic( method.getModifiers() )
|
||||
&& method.getParameterTypes().length == 0
|
||||
&& ( method.getName().startsWith( "get" ) || method.getName().startsWith( "is" ) );
|
||||
}
|
||||
else {
|
||||
return !Modifier.isTransient( m.getModifiers() ) && !m.isSynthetic();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -116,7 +116,6 @@ public class HbmSimpleAttributeDomainState extends AbstractHbmAttributeDomainSta
|
|||
XMLPropertyElement property) {
|
||||
super( defaults, attribute, entityMetaAttributes, property );
|
||||
this.isLazy = property.isLazy();
|
||||
;
|
||||
this.propertyGeneration = PropertyGeneration.parse( property.getGenerated() );
|
||||
|
||||
if ( propertyGeneration == PropertyGeneration.ALWAYS || propertyGeneration == PropertyGeneration.INSERT ) {
|
||||
|
|
|
@ -46,7 +46,7 @@ import static org.junit.Assert.fail;
|
|||
*/
|
||||
public class BasicAnnotationBindingTests extends AbstractBasicBindingTests {
|
||||
|
||||
//@FailureExpected(jiraKey = "HHH-5672", message = "Work in progress")
|
||||
@FailureExpected(jiraKey = "HHH-5672", message = "Work in progress")
|
||||
@Test
|
||||
public void testSimpleEntityMapping() {
|
||||
super.testSimpleEntityMapping();
|
||||
|
|
|
@ -0,0 +1,233 @@
|
|||
package org.hibernate.metamodel.source.annotations.util;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.DotName;
|
||||
import org.jboss.jandex.Index;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.metamodel.source.annotations.ConfiguredClass;
|
||||
import org.hibernate.metamodel.source.annotations.ConfiguredClassHierarchy;
|
||||
import org.hibernate.metamodel.source.annotations.MappedProperty;
|
||||
import org.hibernate.service.ServiceRegistryBuilder;
|
||||
import org.hibernate.service.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.service.internal.BasicServiceRegistryImpl;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public class GenericTypeDiscoveryTest extends BaseUnitTestCase {
|
||||
private BasicServiceRegistryImpl serviceRegistry;
|
||||
private ClassLoaderService service;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
serviceRegistry = (BasicServiceRegistryImpl) new ServiceRegistryBuilder().buildServiceRegistry();
|
||||
service = serviceRegistry.getService( ClassLoaderService.class );
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
serviceRegistry.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleEntity() {
|
||||
Index index = JandexHelper.indexForClass( service, Paper.class, Stuff.class, Item.class, PricedStuff.class );
|
||||
Set<ConfiguredClassHierarchy> hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies(
|
||||
index, serviceRegistry
|
||||
);
|
||||
assertEquals( "There should be only one hierarchy", 1, hierarchies.size() );
|
||||
|
||||
Iterator<ConfiguredClass> iter = hierarchies.iterator().next().iterator();
|
||||
ConfiguredClass configuredClass = iter.next();
|
||||
ClassInfo info = configuredClass.getClassInfo();
|
||||
assertEquals( "wrong class", DotName.createSimple( Stuff.class.getName() ), info.name() );
|
||||
List<MappedProperty> mappedProperties = configuredClass.getMappedProperties();
|
||||
assertTrue( "Stuff should have one mapped property", mappedProperties.size() == 1 );
|
||||
MappedProperty property = mappedProperties.get( 0 );
|
||||
assertEquals( Price.class, property.getType() );
|
||||
|
||||
assertTrue( iter.hasNext() );
|
||||
configuredClass = iter.next();
|
||||
info = configuredClass.getClassInfo();
|
||||
assertEquals( "wrong class", DotName.createSimple( PricedStuff.class.getName() ), info.name() );
|
||||
mappedProperties = configuredClass.getMappedProperties();
|
||||
assertTrue( "PricedStuff should not mapped properties", mappedProperties.size() == 0 );
|
||||
|
||||
assertTrue( iter.hasNext() );
|
||||
configuredClass = iter.next();
|
||||
info = configuredClass.getClassInfo();
|
||||
assertEquals( "wrong class", DotName.createSimple( Item.class.getName() ), info.name() );
|
||||
mappedProperties = configuredClass.getMappedProperties();
|
||||
assertTrue( "Item should have 4 mapped properties", mappedProperties.size() == 4 );
|
||||
// properties are alphabetically ordered!
|
||||
property = mappedProperties.get( 2 );
|
||||
assertEquals( SomeGuy.class, property.getType() );
|
||||
property = mappedProperties.get( 3 );
|
||||
assertEquals( PaperType.class, property.getType() );
|
||||
|
||||
assertTrue( iter.hasNext() );
|
||||
configuredClass = iter.next();
|
||||
info = configuredClass.getClassInfo();
|
||||
assertEquals( "wrong class", DotName.createSimple( Paper.class.getName() ), info.name() );
|
||||
mappedProperties = configuredClass.getMappedProperties();
|
||||
assertTrue( "Paper should not mapped properties", mappedProperties.size() == 0 );
|
||||
|
||||
assertFalse( iter.hasNext() );
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
public class Stuff<Value> {
|
||||
private Value value;
|
||||
|
||||
@ManyToOne
|
||||
public Value getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Value value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
public class PricedStuff extends Stuff<Price> {
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
public class Item<Type, Owner> extends PricedStuff {
|
||||
private Integer id;
|
||||
private String name;
|
||||
private Type type;
|
||||
private Owner owner;
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@ManyToOne
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@ManyToOne
|
||||
public Owner getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(Owner owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Paper extends Item<PaperType, SomeGuy> {
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class PaperType {
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Price {
|
||||
private Integer id;
|
||||
private Double amount;
|
||||
private String currency;
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Double getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(Double amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public String getCurrency() {
|
||||
return currency;
|
||||
}
|
||||
|
||||
public void setCurrency(String currency) {
|
||||
this.currency = currency;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class SomeGuy {
|
||||
private Integer id;
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue