| /* |
| * Copyright (c) 2008, Rickard Öberg. All Rights Reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| package org.apache.zest.api.util; |
| |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.AccessibleObject; |
| import java.lang.reflect.Array; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.GenericArrayType; |
| import java.lang.reflect.Member; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.ParameterizedType; |
| import java.lang.reflect.Type; |
| import java.lang.reflect.TypeVariable; |
| import java.lang.reflect.WildcardType; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import org.apache.zest.api.composite.ModelDescriptor; |
| import org.apache.zest.functional.Function; |
| import org.apache.zest.functional.Iterables; |
| import org.apache.zest.functional.Specification; |
| |
| import static org.apache.zest.functional.Iterables.cast; |
| import static org.apache.zest.functional.Iterables.empty; |
| import static org.apache.zest.functional.Iterables.flatten; |
| import static org.apache.zest.functional.Iterables.flattenIterables; |
| import static org.apache.zest.functional.Iterables.iterable; |
| import static org.apache.zest.functional.Iterables.map; |
| import static org.apache.zest.functional.Iterables.matchesAny; |
| import static org.apache.zest.functional.Iterables.prepend; |
| |
| /** |
| * Useful methods for handling Classes. |
| */ |
| public final class Classes |
| { |
| private final static Map<Type, Type> wrapperClasses = new HashMap<>(); |
| |
| static |
| { |
| wrapperClasses.put( boolean.class, Boolean.class ); |
| wrapperClasses.put( byte.class, Byte.class ); |
| wrapperClasses.put( short.class, Short.class ); |
| wrapperClasses.put( char.class, Character.class ); |
| wrapperClasses.put( int.class, Integer.class ); |
| wrapperClasses.put( long.class, Long.class ); |
| wrapperClasses.put( float.class, Float.class ); |
| wrapperClasses.put( double.class, Double.class ); |
| } |
| |
| private final static Map<Type, Type> primitiveClasses = new HashMap<>(); |
| |
| static |
| { |
| primitiveClasses.put( boolean.class, Boolean.class ); |
| primitiveClasses.put( byte.class, Byte.class ); |
| primitiveClasses.put( short.class, Short.class ); |
| primitiveClasses.put( char.class, Character.class ); |
| primitiveClasses.put( int.class, Integer.class ); |
| primitiveClasses.put( long.class, Long.class ); |
| primitiveClasses.put( float.class, Float.class ); |
| primitiveClasses.put( double.class, Double.class ); |
| } |
| |
| /** |
| * Convert from primitive class (int, short, double, etc.) to wrapper class (Integer, Short, Double, etc.). |
| * Return the same class if it's not a primitive class. This can therefore safely be used on all types |
| * to ensure that they are not primitives. |
| */ |
| private static final Function<Type, Type> WRAPPER_CLASS = new Function<Type, Type>() |
| { |
| @Override |
| public Type map( Type aClass ) |
| { |
| Type wrapperClass = wrapperClasses.get( aClass ); |
| return wrapperClass == null ? aClass : wrapperClass; |
| } |
| }; |
| |
| /** |
| * Convert from wrapper class (Integer, Short, Double, etc.) to primitive class (int, short, double, etc.). |
| * Return the same class if it's not a wrapper class. This can therefore safely be used on all types |
| * to ensure that they are primitives if possible. |
| */ |
| @SuppressWarnings( "UnusedDeclaration" ) |
| private static final Function<Type, Type> PRIMITIVE_CLASS = new Function<Type, Type>() |
| { |
| @Override |
| public Type map( Type aClass ) |
| { |
| Type primitiveClass = primitiveClasses.get( aClass ); |
| return primitiveClass == null ? aClass : primitiveClass; |
| } |
| }; |
| |
| /** |
| * Function that extract the raw class of a type. |
| */ |
| public static final Function<Type, Class<?>> RAW_CLASS = new Function<Type, Class<?>>() |
| { |
| @Override |
| public Class<?> map( Type genericType ) |
| { |
| // Calculate raw type |
| if( genericType instanceof Class ) |
| { |
| return (Class<?>) genericType; |
| } |
| else if( genericType instanceof ParameterizedType ) |
| { |
| return (Class<?>) ( (ParameterizedType) genericType ).getRawType(); |
| } |
| else if( genericType instanceof TypeVariable ) |
| { |
| return (Class<?>) ( (TypeVariable) genericType ).getGenericDeclaration(); |
| } |
| else if( genericType instanceof WildcardType ) |
| { |
| return (Class<?>) ( (WildcardType) genericType ).getUpperBounds()[ 0]; |
| } |
| else if( genericType instanceof GenericArrayType ) |
| { |
| Object temp = Array.newInstance( (Class<?>) ( (GenericArrayType) genericType ).getGenericComponentType(), 0 ); |
| return temp.getClass(); |
| } |
| throw new IllegalArgumentException( "Could not extract the raw class of " + genericType ); |
| } |
| }; |
| |
| private static final Function<AccessibleObject, Type> TYPE_OF = new Function<AccessibleObject, Type>() |
| { |
| @Override |
| public Type map( AccessibleObject accessor ) |
| { |
| return accessor instanceof Method ? ( (Method) accessor ).getGenericReturnType() : ( (Field) accessor ).getGenericType(); |
| } |
| }; |
| |
| private static final Function<Type, Iterable<Class<?>>> CLASS_HIERARCHY = new Function<Type, Iterable<Class<?>>>() |
| { |
| @Override |
| @SuppressWarnings( {"raw", "unchecked"} ) |
| public Iterable<Class<?>> map( Type type ) |
| { |
| if( type == null ) |
| { |
| return empty(); |
| } |
| if( type.equals( Object.class ) ) |
| { |
| Class<?> aClass = (Class<?>) type; |
| return cast( iterable( aClass ) ); |
| } |
| else |
| { |
| type = RAW_CLASS.map( type ); |
| Class superclass = ( (Class) type ).getSuperclass(); |
| return prepend( (Class<?>) type, map( superclass ) ); |
| } |
| } |
| }; |
| |
| @SuppressWarnings( "raw" ) |
| private static final Function<Type, Iterable<Type>> INTERFACES_OF = new Function<Type, Iterable<Type>>() |
| { |
| @Override |
| public Iterable<Type> map( Type type ) |
| { |
| Class clazz = RAW_CLASS.map( type ); |
| |
| if( clazz.isInterface() ) |
| { |
| Iterable<Type> genericInterfaces = iterable( clazz.getGenericInterfaces() ); |
| Iterable<Type> flattenIterables = flattenIterables( Iterables.map( INTERFACES_OF, genericInterfaces ) ); |
| return prepend( type, flattenIterables ); |
| } |
| else |
| { |
| if( type.equals( Object.class ) ) |
| { |
| return iterable( clazz.getGenericInterfaces() ); |
| } |
| else |
| { |
| return flatten( flattenIterables( Iterables.map( INTERFACES_OF, |
| iterable( clazz.getGenericInterfaces() ) ) ), |
| INTERFACES_OF.map( RAW_CLASS.map( type ).getSuperclass() ) ); |
| } |
| } |
| } |
| }; |
| |
| @SuppressWarnings( "raw" ) |
| private static final Function<Type, Iterable<Type>> TYPES_OF = new Function<Type, Iterable<Type>>() |
| { |
| @Override |
| public Iterable<Type> map( Type type ) |
| { |
| Class clazz = RAW_CLASS.map( type ); |
| |
| if( clazz.isInterface() ) |
| { |
| Iterable<Type> genericInterfaces = iterable( clazz.getGenericInterfaces() ); |
| Iterable<Type> flattenIterables = flattenIterables( Iterables.map( INTERFACES_OF, genericInterfaces ) ); |
| return prepend( clazz, flattenIterables ); |
| } |
| else |
| { |
| return flatten( CLASS_HIERARCHY.map( type ), |
| flattenIterables( Iterables.map( INTERFACES_OF, CLASS_HIERARCHY.map( type ) ) ) ); |
| } |
| } |
| }; |
| |
| public static Type typeOf( AccessibleObject from ) |
| { |
| return TYPE_OF.map( from ); |
| } |
| |
| public static Iterable<Type> typesOf( Iterable<Type> types ) |
| { |
| Iterable<Type> result = empty(); |
| for( Type type : types ) |
| { |
| result = flatten( result, typesOf( type ) ); |
| } |
| return result; |
| } |
| |
| public static Iterable<Type> typesOf( Type type ) |
| { |
| return TYPES_OF.map( type ); |
| } |
| |
| public static Iterable<? extends Type> interfacesOf( Iterable<? extends Type> types ) |
| { |
| Iterable<Type> result = empty(); |
| for( Type type : types ) |
| { |
| result = flatten( result, interfacesOf( type ) ); |
| } |
| return result; |
| } |
| |
| public static Iterable<Type> interfacesOf( Type type ) |
| { |
| return INTERFACES_OF.map( type ); |
| } |
| |
| public static Iterable<Class<?>> classHierarchy( Class<?> type ) |
| { |
| return CLASS_HIERARCHY.map( type ); |
| } |
| |
| public static Type wrapperClass( Type type ) |
| { |
| return WRAPPER_CLASS.map( type ); |
| } |
| |
| public static Specification<Class<?>> isAssignableFrom( final Class clazz ) |
| { |
| return new Specification<Class<?>>() |
| { |
| @Override |
| @SuppressWarnings( "unchecked" ) |
| public boolean satisfiedBy( Class<?> item ) |
| { |
| return clazz.isAssignableFrom( item ); |
| } |
| }; |
| } |
| |
| @SuppressWarnings( "raw" ) |
| public static Specification<Object> instanceOf( final Class clazz ) |
| { |
| return new Specification<Object>() |
| { |
| @Override |
| public boolean satisfiedBy( Object item ) |
| { |
| return clazz.isInstance( item ); |
| } |
| }; |
| } |
| |
| public static Specification<Class<?>> hasModifier( final int classModifier ) |
| { |
| return new Specification<Class<?>>() |
| { |
| @Override |
| public boolean satisfiedBy( Class<?> item ) |
| { |
| return ( item.getModifiers() & classModifier ) != 0; |
| } |
| }; |
| } |
| |
| public static <T> Function<Type, Iterable<T>> forClassHierarchy( final Function<Class<?>, Iterable<T>> function ) |
| { |
| return new Function<Type, Iterable<T>>() |
| { |
| @Override |
| public Iterable<T> map( Type type ) |
| { |
| return flattenIterables( Iterables.map( function, CLASS_HIERARCHY.map( type ) ) ); |
| } |
| }; |
| } |
| |
| public static <T> Function<Type, Iterable<T>> forTypes( final Function<Type, Iterable<T>> function ) |
| { |
| return new Function<Type, Iterable<T>>() |
| { |
| @Override |
| public Iterable<T> map( Type type ) |
| { |
| return flattenIterables( Iterables.map( function, TYPES_OF.map( type ) ) ); |
| } |
| }; |
| } |
| |
| @SuppressWarnings( "raw" ) |
| public static Set<Class<?>> interfacesWithMethods( Set<Class<?>> interfaces ) |
| { |
| Set<Class<?>> newSet = new LinkedHashSet<>(); |
| for( Class type : interfaces ) |
| { |
| if( type.isInterface() && type.getDeclaredMethods().length > 0 ) |
| { |
| newSet.add( type ); |
| } |
| } |
| |
| return newSet; |
| } |
| |
| public static String simpleGenericNameOf( Type type ) |
| { |
| StringBuilder sb = new StringBuilder(); |
| simpleGenericNameOf( sb, type ); |
| return sb.toString(); |
| } |
| |
| @SuppressWarnings( "raw" ) |
| private static void simpleGenericNameOf( StringBuilder sb, Type type ) |
| { |
| if( type instanceof Class ) |
| { |
| sb.append( ( (Class) type ).getSimpleName() ); |
| } |
| else if( type instanceof ParameterizedType ) |
| { |
| ParameterizedType pt = (ParameterizedType) type; |
| simpleGenericNameOf( sb, pt.getRawType() ); |
| sb.append( "<" ); |
| boolean atLeastOne = false; |
| for( Type typeArgument : pt.getActualTypeArguments() ) |
| { |
| if( atLeastOne ) |
| { |
| sb.append( ", " ); |
| } |
| simpleGenericNameOf( sb, typeArgument ); |
| atLeastOne = true; |
| } |
| sb.append( ">" ); |
| } |
| else if( type instanceof GenericArrayType ) |
| { |
| GenericArrayType gat = (GenericArrayType) type; |
| simpleGenericNameOf( sb, gat.getGenericComponentType() ); |
| sb.append( "[]" ); |
| } |
| else if( type instanceof TypeVariable ) |
| { |
| TypeVariable tv = (TypeVariable) type; |
| sb.append( tv.getName() ); |
| } |
| else if( type instanceof WildcardType ) |
| { |
| WildcardType wt = (WildcardType) type; |
| sb.append( "? extends " ); |
| boolean atLeastOne = false; |
| for( Type typeArgument : wt.getUpperBounds() ) |
| { |
| if( atLeastOne ) |
| { |
| sb.append( ", " ); |
| } |
| simpleGenericNameOf( sb, typeArgument ); |
| atLeastOne = true; |
| } |
| } |
| else |
| { |
| throw new IllegalArgumentException( "Don't know how to deal with type:" + type ); |
| } |
| } |
| |
| @SuppressWarnings( "UnusedDeclaration" ) |
| public static <AnnotationType extends Annotation> |
| AnnotationType findAnnotationOfTypeOrAnyOfSuperTypes( Class<?> type, Class<AnnotationType> annotationClass ) |
| { |
| AnnotationType result = null; |
| for( Type clazz : Classes.TYPES_OF.map( type ) ) |
| { |
| result = Classes.RAW_CLASS.map( clazz ).getAnnotation( annotationClass ); |
| if( result != null ) |
| { |
| break; |
| } |
| } |
| |
| return result; |
| } |
| |
| public static Specification<Member> memberNamed( final String name ) |
| { |
| return new Specification<Member>() |
| { |
| @Override |
| public boolean satisfiedBy( Member item ) |
| { |
| return item.getName().equals( name ); |
| } |
| }; |
| } |
| |
| /** |
| * Given a type variable, find what it resolves to given the declaring class where type |
| * variable was found and a top class that extends the declaring class. |
| * |
| * @param name The TypeVariable name. |
| * @param declaringClass The class where the TypeVariable is declared. |
| * @param topClass The top class that extends the declaringClass |
| * |
| * @return The Type instance of the given TypeVariable |
| */ |
| @SuppressWarnings( "raw" ) |
| public static Type resolveTypeVariable( TypeVariable name, Class declaringClass, Class topClass ) |
| { |
| Type type = resolveTypeVariable( name, declaringClass, new HashMap<TypeVariable, Type>(), topClass ); |
| if( type == null ) |
| { |
| type = Object.class; |
| } |
| return type; |
| } |
| |
| @SuppressWarnings( "raw" ) |
| private static Type resolveTypeVariable( TypeVariable name, |
| Class declaringClass, |
| Map<TypeVariable, Type> mappings, |
| Class current |
| ) |
| { |
| if( current.equals( declaringClass ) ) |
| { |
| Type resolvedType = name; |
| while( resolvedType instanceof TypeVariable ) |
| { |
| resolvedType = mappings.get( resolvedType ); |
| } |
| return resolvedType; |
| } |
| |
| List<Type> types = new ArrayList<>(); |
| for( Type type : current.getGenericInterfaces() ) |
| { |
| Iterable<Type> interfaces = Classes.INTERFACES_OF.map( type ); |
| for( Type anInterface : interfaces ) |
| { |
| if( !types.contains( anInterface ) ) |
| { |
| types.add( anInterface ); |
| } |
| } |
| types.add( type ); |
| } |
| |
| if( current.getGenericSuperclass() != null ) |
| { |
| types.add( current.getGenericSuperclass() ); |
| } |
| |
| for( Type type : types ) |
| { |
| Class subClass; |
| if( type instanceof ParameterizedType ) |
| { |
| ParameterizedType pt = (ParameterizedType) type; |
| Type[] args = pt.getActualTypeArguments(); |
| Class clazz = (Class) pt.getRawType(); |
| TypeVariable[] vars = clazz.getTypeParameters(); |
| for( int i = 0; i < vars.length; i++ ) |
| { |
| TypeVariable var = vars[ i]; |
| Type mappedType = args[ i]; |
| mappings.put( var, mappedType ); |
| } |
| subClass = (Class) pt.getRawType(); |
| } |
| else |
| { |
| subClass = (Class) type; |
| } |
| |
| Type resolvedType = resolveTypeVariable( name, declaringClass, mappings, subClass ); |
| if( resolvedType != null ) |
| { |
| return resolvedType; |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Get URI for a class. |
| * |
| * @param clazz class |
| * |
| * @return URI |
| * |
| * @throws NullPointerException if clazz is null |
| */ |
| @SuppressWarnings( "raw" ) |
| public static String toURI( final Class clazz ) |
| throws NullPointerException |
| { |
| return toURI( clazz.getName() ); |
| } |
| |
| /** |
| * Get URI for a class name. |
| * <p> |
| * Example: |
| * </p> |
| * <p> |
| * Class name com.example.Foo$Bar is converted to URI urn:qi4j:com.example.Foo-Bar |
| * </p> |
| * |
| * @param className class name |
| * |
| * @return URI |
| * |
| * @throws NullPointerException if className is null |
| */ |
| public static String toURI( String className ) |
| throws NullPointerException |
| { |
| className = normalizeClassToURI( className ); |
| return "urn:qi4j:type:" + className; |
| } |
| |
| /** |
| * Get class name from a URI |
| * |
| * @param uri URI |
| * |
| * @return class name |
| * |
| * @throws NullPointerException if uri is null |
| */ |
| public static String toClassName( String uri ) |
| throws NullPointerException |
| { |
| uri = uri.substring( "urn:qi4j:type:".length() ); |
| uri = denormalizeURIToClass( uri ); |
| return uri; |
| } |
| |
| public static String normalizeClassToURI( String className ) |
| { |
| return className.replace( '$', '-' ); |
| } |
| |
| public static String denormalizeURIToClass( String uriPart ) |
| { |
| return uriPart.replace( '-', '$' ); |
| } |
| |
| public static Specification<ModelDescriptor> modelTypeSpecification( final String className ) |
| { |
| return new Specification<ModelDescriptor>() |
| { |
| @Override |
| public boolean satisfiedBy( ModelDescriptor item ) |
| { |
| return matchesAny( new Specification<String>() |
| { |
| @Override |
| public boolean satisfiedBy( String item ) |
| { |
| return item.equals( className ); |
| } |
| }, map( new Function<Class<?>, String>() |
| { |
| @Override |
| public String map( Class<?> item ) |
| { |
| return item.getName(); |
| } |
| }, item.types() ) ); |
| } |
| }; |
| } |
| |
| @SuppressWarnings( "raw" ) |
| public static Specification<ModelDescriptor> exactTypeSpecification( final Class type ) |
| { |
| return new Specification<ModelDescriptor>() |
| { |
| @Override |
| public boolean satisfiedBy( ModelDescriptor item ) |
| { |
| return matchesAny( new Specification<Class<?>>() |
| { |
| @Override |
| public boolean satisfiedBy( Class<?> item ) |
| { |
| return item.equals( type ); |
| } |
| }, item.types() ); |
| } |
| }; |
| } |
| |
| @SuppressWarnings( "raw" ) |
| public static Specification<ModelDescriptor> assignableTypeSpecification( final Class type ) |
| { |
| return new Specification<ModelDescriptor>() |
| { |
| @Override |
| public boolean satisfiedBy( ModelDescriptor item ) |
| { |
| return matchesAny( new Specification<Class<?>>() |
| { |
| @Override |
| @SuppressWarnings( "unchecked" ) |
| public boolean satisfiedBy( Class<?> itemType ) |
| { |
| return !type.equals( itemType ) && type.isAssignableFrom( itemType ); |
| } |
| }, item.types() ); |
| } |
| }; |
| } |
| |
| @SuppressWarnings( "raw" ) |
| public static String toString( Iterable<? extends Class> type ) |
| { |
| StringBuilder builder = new StringBuilder(); |
| builder.append( "[" ); |
| boolean first = true; |
| for( Class c : type ) |
| { |
| if( !first ) |
| { |
| builder.append( "," ); |
| } |
| first = false; |
| builder.append( c.getSimpleName() ); |
| } |
| builder.append( "]" ); |
| return builder.toString(); |
| } |
| |
| public static Function<Type, String> toClassName() |
| { |
| return new Function<Type, String>() |
| { |
| @Override |
| public String map( Type type ) |
| { |
| return RAW_CLASS.map( type ).getName(); |
| } |
| }; |
| } |
| |
| private Classes() |
| { |
| } |
| } |