Skip to content

Instantly share code, notes, and snippets.

@impl
Created January 26, 2013 09:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save impl/4641219 to your computer and use it in GitHub Desktop.
Save impl/4641219 to your computer and use it in GitHub Desktop.
Utility class for analyzing type information in Java
/* 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