From: <pao...@us...> - 2006-02-13 19:14:44
|
Update of /cvsroot/hibernate/HibernateExt/metadata/src/java/org/hibernate/reflection/java/generics In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21308/metadata/src/java/org/hibernate/reflection/java/generics Modified Files: IdentityTypeEnvironment.java TypeSwitch.java SimpleTypeEnvironment.java CompoundTypeEnvironment.java TypeEnvironment.java Added Files: TypeEnvironmentFactory.java Removed Files: GenericsEnvironment.java Log Message: Support for generics in reflection layer --- NEW FILE: TypeEnvironmentFactory.java --- package org.hibernate.reflection.java.generics; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.HashMap; import java.util.Map; /** * Returns the type context for a given <code>Class</code> or <code>ParameterizedType</code>. * <p> * Does not support bindings involving inner classes, nor upper/lower bounds. * * @author Davide Marchignoli * @author Paolo Perrotta */ public class TypeEnvironmentFactory { private final Map<Type, TypeEnvironment> typeToEnvironment = new HashMap<Type, TypeEnvironment>(); /** * @return Returns a type environment suitable for resolving types occurring * in subclasses of the context class. */ public TypeEnvironment getEnvironment(Class context) { return doGetEnvironment( context ); } public TypeEnvironment getEnvironment(ParameterizedType context) { return doGetEnvironment( context ); } private TypeEnvironment doGetEnvironment(Type context) { if ( context == null ) return IdentityTypeEnvironment.INSTANCE; TypeEnvironment result = typeToEnvironment.get( context ); if ( result == null ) { result = createEnvironment( context ); typeToEnvironment.put( context, result ); } return result; } private TypeEnvironment createEnvironment(Type context) { return new TypeSwitch<TypeEnvironment>() { @Override public TypeEnvironment caseClass(Class classType) { return new CompoundTypeEnvironment( createSuperTypeEnvironment( classType ), getEnvironment( classType.getSuperclass() ) ); } @Override public TypeEnvironment caseParameterizedType(ParameterizedType parameterizedType) { return createEnvironment( parameterizedType ); } @Override public TypeEnvironment defaultCase(Type t) { throw new IllegalArgumentException( "Invalid type for generating environment: " + t ); } }.doSwitch( context ); } private TypeEnvironment createSuperTypeEnvironment(Class clazz) { Class superclass = clazz.getSuperclass(); if ( superclass == null ) return IdentityTypeEnvironment.INSTANCE; Type[] formalArgs = superclass.getTypeParameters(); Type genericSuperclass = clazz.getGenericSuperclass(); if ( genericSuperclass instanceof Class ) return IdentityTypeEnvironment.INSTANCE; if ( genericSuperclass instanceof ParameterizedType ) { Type[] actualArgs = ( (ParameterizedType) genericSuperclass ).getActualTypeArguments(); return new SimpleTypeEnvironment( formalArgs, actualArgs ); } throw new AssertionError( "Should be unreachable" ); } private TypeEnvironment createEnvironment(ParameterizedType t) { Type[] tactuals = t.getActualTypeArguments(); Type rawType = t.getRawType(); if ( rawType instanceof Class ) { TypeVariable[] tparms = ( (Class) rawType ).getTypeParameters(); return new SimpleTypeEnvironment( tparms, tactuals ); } return IdentityTypeEnvironment.INSTANCE; } } Index: IdentityTypeEnvironment.java =================================================================== RCS file: /cvsroot/hibernate/HibernateExt/metadata/src/java/org/hibernate/reflection/java/generics/IdentityTypeEnvironment.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- IdentityTypeEnvironment.java 1 Feb 2006 13:43:33 -0000 1.1 +++ IdentityTypeEnvironment.java 13 Feb 2006 19:14:35 -0000 1.2 @@ -3,19 +3,19 @@ import java.lang.reflect.Type; /** - * Substitutes a <tt>Type</tt> for itself. + * Substitutes a <code>Type</code> for itself. * * @author Davide Marchignoli * @author Paolo Perrotta */ -class IdentityTypeEnvironment implements TypeEnvironment { +public class IdentityTypeEnvironment implements TypeEnvironment { public static final TypeEnvironment INSTANCE = new IdentityTypeEnvironment(); private IdentityTypeEnvironment() { } - public Type substitute(Type type) { + public Type bind(Type type) { return type; } } Index: TypeSwitch.java =================================================================== RCS file: /cvsroot/hibernate/HibernateExt/metadata/src/java/org/hibernate/reflection/java/generics/TypeSwitch.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- TypeSwitch.java 1 Feb 2006 13:43:33 -0000 1.1 +++ TypeSwitch.java 13 Feb 2006 19:14:35 -0000 1.2 @@ -7,39 +7,48 @@ import java.lang.reflect.WildcardType; /** - * A visitor for the <tt>java.lang.reflect.Type</tt> hierarchy. + * A visitor for the <code>java.lang.reflect.Type</code> hierarchy. * * @author Davide Marchignoli * @author Paolo Perrotta */ -abstract class TypeSwitch<T> { +public class TypeSwitch<T> { - public final T visit(Type type) { - if ( type instanceof Class ) { + public final T doSwitch(Type type) { + if ( type instanceof Class ) return caseClass( (Class) type ); - } - else if ( type instanceof GenericArrayType ) { + if ( type instanceof GenericArrayType ) return caseGenericArrayType( (GenericArrayType) type ); - } - else if ( type instanceof ParameterizedType ) { + if ( type instanceof ParameterizedType ) return caseParameterizedType( (ParameterizedType) type ); - } - else if ( type instanceof TypeVariable ) { + if ( type instanceof TypeVariable ) return caseTypeVariable( (TypeVariable) type ); - } - else if ( type instanceof WildcardType ) { + if ( type instanceof WildcardType ) return caseWildcardType( (WildcardType) type ); - } - throw new IllegalArgumentException( "Unexpected Type: " + type ); + return defaultCase( type ); } - public abstract T caseWildcardType(WildcardType wildcardType); + public T caseWildcardType(WildcardType wildcardType) { + return defaultCase( wildcardType ); + } - public abstract T caseTypeVariable(TypeVariable typeVariable); + public T caseTypeVariable(TypeVariable typeVariable) { + return defaultCase( typeVariable ); + } - public abstract T caseClass(Class classType); + public T caseClass(Class classType) { + return defaultCase( classType ); + } - public abstract T caseGenericArrayType(GenericArrayType genericArrayType); + public T caseGenericArrayType(GenericArrayType genericArrayType) { + return defaultCase( genericArrayType ); + } - public abstract T caseParameterizedType(ParameterizedType parameterizedType); + public T caseParameterizedType(ParameterizedType parameterizedType) { + return defaultCase( parameterizedType ); + } + + public T defaultCase(Type t) { + return null; + } } Index: SimpleTypeEnvironment.java =================================================================== RCS file: /cvsroot/hibernate/HibernateExt/metadata/src/java/org/hibernate/reflection/java/generics/SimpleTypeEnvironment.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- SimpleTypeEnvironment.java 1 Feb 2006 13:43:33 -0000 1.1 +++ SimpleTypeEnvironment.java 13 Feb 2006 19:14:35 -0000 1.2 @@ -5,6 +5,7 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; +import java.util.Arrays; /** * @author Davide Marchignoli @@ -24,14 +25,13 @@ @Override public Type caseGenericArrayType(GenericArrayType genericArrayType) { - return createGenericArrayType( substitute( genericArrayType.getGenericComponentType() ) ); + return createGenericArrayType( bind( genericArrayType.getGenericComponentType() ) ); } @Override public Type caseParameterizedType(ParameterizedType parameterizedType) { - return createParameterizedType( parameterizedType.getRawType(), - substitute( parameterizedType.getActualTypeArguments() ), - parameterizedType.getOwnerType() ); + return createParameterizedType( parameterizedType.getRawType(), substitute( parameterizedType + .getActualTypeArguments() ), parameterizedType.getOwnerType() ); } @Override @@ -58,12 +58,12 @@ formalArguments = formal; } - // We instance our own ParameterizedTypes and GenericArrayType. These instances are not - // supposed to be mixed with Java's own. If they did, we might have trouble with - // equality/identity when checking against Java's implementations. - - protected ParameterizedType createParameterizedType(final Type rawType, - final Type[] substTypeArgs, final Type ownerType) { + // We instance our own ParameterizedTypes and GenericArrayType. These + // are not supposed to be mixed with Java's implementations. If they + // did, we might have equality/identity problems. + + private ParameterizedType createParameterizedType(final Type rawType, final Type[] substTypeArgs, + final Type ownerType) { return new ParameterizedType() { public Type[] getActualTypeArguments() { @@ -77,6 +77,18 @@ public Type getOwnerType() { return ownerType; } + + @Override + public boolean equals(Object obj) { + ParameterizedType other = (ParameterizedType) obj; + return Arrays.equals( getActualTypeArguments(), other.getActualTypeArguments() ) + && getRawType().equals( other.getRawType() ) && getOwnerType().equals( other.getOwnerType() ); + } + + @Override + public int hashCode() { + return safeHashCode( getActualTypeArguments() ) ^ safeHashCode( getRawType() ) ^ safeHashCode( getOwnerType() ); + } }; } @@ -86,17 +98,34 @@ public Type getGenericComponentType() { return componentType; } + + @Override + public boolean equals(Object obj) { + GenericArrayType other = (GenericArrayType) obj; + return getGenericComponentType().equals( other.getGenericComponentType() ); + } + + @Override + public int hashCode() { + return safeHashCode( getGenericComponentType() ); + } }; } - public Type substitute(Type type) { - return substitute.visit( type ); + private int safeHashCode(Object o) { + if( o == null ) + return 1; + return o.hashCode(); } - public Type[] substitute(Type[] types) { + public Type bind(Type type) { + return substitute.doSwitch( type ); + } + + private Type[] substitute(Type[] types) { Type[] substTypes = new Type[types.length]; for ( int i = 0; i < substTypes.length; i++ ) - substTypes[i] = substitute( types[i] ); + substTypes[i] = bind( types[i] ); return substTypes; } } Index: CompoundTypeEnvironment.java =================================================================== RCS file: /cvsroot/hibernate/HibernateExt/metadata/src/java/org/hibernate/reflection/java/generics/CompoundTypeEnvironment.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- CompoundTypeEnvironment.java 1 Feb 2006 13:43:33 -0000 1.1 +++ CompoundTypeEnvironment.java 13 Feb 2006 19:14:35 -0000 1.2 @@ -3,7 +3,7 @@ import java.lang.reflect.Type; /** - * A composition of two <tt>TypeEnvironment</tt> functions. + * A composition of two <code>TypeEnvironment</code> functions. * * @author Davide Marchignoli * @author Paolo Perrotta @@ -19,7 +19,7 @@ this.g = g; } - public Type substitute(Type type) { - return f.substitute( g.substitute( type ) ); + public Type bind(Type type) { + return f.bind( g.bind( type ) ); } } Index: TypeEnvironment.java =================================================================== RCS file: /cvsroot/hibernate/HibernateExt/metadata/src/java/org/hibernate/reflection/java/generics/TypeEnvironment.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- TypeEnvironment.java 1 Feb 2006 13:43:33 -0000 1.1 +++ TypeEnvironment.java 13 Feb 2006 19:14:35 -0000 1.2 @@ -3,10 +3,51 @@ import java.lang.reflect.Type; /** + * A typing context that knows how to "resolve" the generic parameters of a + * <code>Type</code>. + * <p> + * For example: + * <p> + * + * <blockquote> + * + * <pre> + * class Shop&ltT&gt{ + * List&ltT&gt getCatalog() { ... } + * } + * + * class Bakery extends Shop&ltBread&gt{} + * </pre> + * + * </blockquote> + * + * Consider the type returned by method <code>getCatalog()</code>. There are + * two possible contexts here. In the context of <code>Shop</code>, the type + * is <code>List<T></code>. In the context of <code>Bakery</code>, the + * type is <code>List<Bread></code>. Each of these contexts can be + * represented by a <code>TypeEnvironment</code>. + * * @author Davide Marchignoli * @author Paolo Perrotta */ -interface TypeEnvironment { +public interface TypeEnvironment { - public Type substitute(Type type); + /** + * Binds as many generic components of the given type as possible in this + * context. + * <p> + * Warning: if the returned <code>Type</code> is a <code>Class</code>, + * then it's guaranteed to be a regular Java <code>Class</code>. In all + * other cases, this method might return a custom implementation of some + * interface that extends <code>Type</code>. Be sure not to mix these + * objects with with Java's implementations of <code>Type</code> to avoid + * potential identity problems. + * <p> + * This class does not support bindings involving inner classes or + * upper/lower bounds. + * + * @return a type where the generic arguments have been replaced by raw + * classes whenever this is possible. + */ + public Type bind(Type type); } \ No newline at end of file --- GenericsEnvironment.java DELETED --- |