Created
January 26, 2013 09:07
-
-
Save impl/4641219 to your computer and use it in GitHub Desktop.
Utility class for analyzing type information in Java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* This file incorporates portions of JBoss Weld, the JSR-299 reference | |
* implementation. | |
* | |
* JBoss, Home of Professional Open Source | |
* Copyright 2008, Red Hat, Inc., and individual contributors | |
* by the @authors tag. See the copyright.txt in the distribution for a | |
* full listing of individual contributors. | |
* | |
* 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 com.cynigram; | |
import java.lang.reflect.ParameterizedType; | |
import java.lang.reflect.Type; | |
import java.lang.reflect.TypeVariable; | |
import java.lang.reflect.WildcardType; | |
import java.util.Arrays; | |
/** | |
* @author Pete Muir | |
*/ | |
public class Introspections { | |
private Introspections() {} | |
public static boolean matches(Type type1, Type type2) { | |
if(type1 instanceof Class<?>) { | |
Class<?> clazz = (Class<?>)type1; | |
if(matches(clazz, new Type[0], type2)) | |
return true; | |
} | |
else if(type1 instanceof ParameterizedType) { | |
ParameterizedType pt = (ParameterizedType)type1; | |
if(pt.getRawType() instanceof Class<?>) { | |
Class<?> clazz = (Class<?>)pt.getRawType(); | |
if(matches(clazz, pt.getActualTypeArguments(), type2)) | |
return true; | |
} | |
} | |
else if(type1 instanceof WildcardType) { | |
WildcardType wt = (WildcardType)type1; | |
if(isBounded(type2, wt.getLowerBounds(), wt.getUpperBounds())) | |
return true; | |
} | |
else if(type1 instanceof TypeVariable<?>) { | |
TypeVariable<?> tv = (TypeVariable<?>)type1; | |
if(isBounded(type2, new Type[0], tv.getBounds())) | |
return true; | |
} | |
// Other possibilities for certain values of to parameter | |
if(type2 instanceof WildcardType) { | |
WildcardType wt = (WildcardType)type2; | |
if(isBounded(type1, wt.getUpperBounds(), wt.getLowerBounds())) | |
return true; | |
} | |
else if(type2 instanceof TypeVariable<?>) { | |
TypeVariable<?> tv = (TypeVariable<?>)type2; | |
if(isBounded(type1, tv.getBounds(), new Type[0])) | |
return true; | |
} | |
return false; | |
} | |
public static boolean isAssignableFrom(Type from, Type to) { | |
if(from instanceof Class<?>) { | |
Class<?> clazz = (Class<?>)from; | |
if(isAssignableFrom(clazz, new Type[0], to)) | |
return true; | |
} | |
else if(from instanceof ParameterizedType) { | |
ParameterizedType pt = (ParameterizedType)from; | |
if(pt.getRawType() instanceof Class<?>) { | |
Class<?> clazz = (Class<?>)pt.getRawType(); | |
if(isAssignableFrom(clazz, pt.getActualTypeArguments(), to)) | |
return true; | |
} | |
} | |
else if(from instanceof WildcardType) { | |
WildcardType wt = (WildcardType)from; | |
if(isBounded(to, wt.getLowerBounds(), wt.getUpperBounds())) | |
return true; | |
} | |
else if(from instanceof TypeVariable<?>) { | |
TypeVariable<?> tv = (TypeVariable<?>)from; | |
if(isBounded(to, new Type[0], tv.getBounds())) | |
return true; | |
} | |
// Other possibilities for certain values of to parameter | |
if(to instanceof WildcardType) { | |
WildcardType wt = (WildcardType)to; | |
if(isBounded(from, wt.getUpperBounds(), wt.getLowerBounds())) | |
return true; | |
} | |
else if(to instanceof TypeVariable<?>) { | |
TypeVariable<?> tv = (TypeVariable<?>)to; | |
if(isBounded(from, tv.getBounds(), new Type[0])) | |
return true; | |
} | |
return false; | |
} | |
private static boolean matches(Class<?> type1, Type[] type1Parameters, Type type2) { | |
if(type2 instanceof Class<?>) { | |
Class<?> clazz = (Class<?>)type2; | |
return matches(type1, type1Parameters, clazz, new Type[0]); | |
} | |
else if(type2 instanceof ParameterizedType) { | |
ParameterizedType pt = (ParameterizedType)type2; | |
return pt.getRawType() instanceof Class<?> && | |
matches(type1, type1Parameters, (Class<?>)pt.getRawType(), pt.getActualTypeArguments()); | |
} | |
else if(type2 instanceof TypeVariable<?>) { | |
TypeVariable<?> tv = (TypeVariable<?>)type2; | |
return isBounded(type1, type1Parameters, tv.getBounds()); | |
} | |
return false; | |
} | |
private static boolean isAssignableFrom(Class<?> from, Type[] fromParameters, Type to) { | |
if(to instanceof Class<?>) { | |
Class<?> clazz = (Class<?>)to; | |
return isAssignableFrom(from, fromParameters, clazz, new Type[0]); | |
} | |
else if(to instanceof ParameterizedType) { | |
ParameterizedType pt = (ParameterizedType)to; | |
return pt.getRawType() instanceof Class<?> && | |
isAssignableFrom(from, fromParameters, (Class<?>)pt.getRawType(), pt.getActualTypeArguments()); | |
} | |
else if(to instanceof TypeVariable<?>) { | |
TypeVariable<?> tv = (TypeVariable<?>)to; | |
return isBounded(from, fromParameters, tv.getBounds()); | |
} | |
return false; | |
} | |
private static boolean matches(Class<?> from, Type[] fromParameters, Class<?> to, Type[] toParameters) { | |
return boxed(from).equals(boxed(to)) && areTypeParametersAssignableFrom(fromParameters, toParameters); | |
} | |
private static boolean isAssignableFrom(Class<?> from, Type[] fromParameters, Class<?> to, Type[] toParameters) { | |
return boxed(from).isAssignableFrom(boxed(to)) && areTypeParametersAssignableFrom(fromParameters, toParameters); | |
} | |
private static boolean isAssignableFromAny(Type[] froms, Type to) { | |
for(Type from : froms) { | |
if(isAssignableFrom(from, to)) | |
return true; | |
} | |
return false; | |
} | |
private static boolean areAnyAssignableFrom(Type from, Type[] tos) { | |
for(Type to : tos) { | |
if(isAssignableFrom(from, to)) | |
return true; | |
} | |
return false; | |
} | |
private static boolean areTypeParametersAssignableFrom(Type[] froms, Type[] tos) { | |
if(tos.length == 0) { | |
tos = new Type[froms.length]; | |
Arrays.fill(tos, Object.class); | |
} | |
else if(froms.length != tos.length) | |
return false; | |
for(int i = 0; i < froms.length; i++) { | |
if(!isAssignableFrom(froms[i], tos[i])) | |
return false; | |
} | |
return true; | |
} | |
private static boolean isBounded(Type type, Type[] lowerBounds, Type[] upperBounds) { | |
if(lowerBounds.length > 0) { | |
if(!areAnyAssignableFrom(type, lowerBounds)) | |
return false; | |
} | |
if(upperBounds.length > 0) { | |
if(!isAssignableFromAny(upperBounds, type)) | |
return false; | |
} | |
return true; | |
} | |
public static Type boxed(Type type) { | |
if(!(type instanceof Class<?>)) | |
return type; | |
return boxed((Class<?>)type); | |
} | |
public static Class<?> boxed(Class<?> type) { | |
if(!type.isPrimitive()) { | |
return type; | |
} | |
else if(type.equals(Boolean.TYPE)) { | |
return Boolean.class; | |
} | |
else if(type.equals(Character.TYPE)) { | |
return Character.class; | |
} | |
else if(type.equals(Byte.TYPE)) { | |
return Byte.class; | |
} | |
else if(type.equals(Short.TYPE)) { | |
return Short.class; | |
} | |
else if(type.equals(Integer.TYPE)) { | |
return Integer.class; | |
} | |
else if(type.equals(Long.TYPE)) { | |
return Long.class; | |
} | |
else if(type.equals(Float.TYPE)) { | |
return Float.class; | |
} | |
else if(type.equals(Double.TYPE)) { | |
return Double.class; | |
} | |
else if(type.equals(Void.TYPE)) { | |
return Void.class; | |
} | |
// Introducing a new primitive is forbidden! | |
throw new IllegalArgumentException("Unknown primitive type '" + type.getName() + "'"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment