All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.nullschool.grains.generate.Cook Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2013 Cameron Beccario
 *
 * 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 net.nullschool.grains.generate;

import net.nullschool.reflect.*;

import java.lang.reflect.*;
import java.util.HashSet;
import java.util.Set;

import static net.nullschool.reflect.TypeTools.erase;
import static net.nullschool.reflect.TypeTools.isInnerClass;


/**
 * 2013-03-29

* * An operator that instantiates raw types into equivalent parameterized types. For example, the raw type * {@code List} should be considered {@code List<? extends Object>} for certain purposes, such as verifying * the type represents an immutable type. Other examples: *

 * Map      ->  Map<? extends Object, ? extends Object>
 * EnumSet  ->  EnumSet<? extends Enum>
 * 
* This class is not thread safe. * * @author Cameron Beccario */ class Cook extends AbstractTypeOperator { /** * Keeps track of type variables currently being instantiated, for cycle detection. */ private final Set> activeVariables = new HashSet<>(); @Override public Type apply(Class clazz) { if (clazz.isArray()) { // Cook arrays that might have generic component types, like List[]. Type componentType = apply(clazz.getComponentType()); if (!(componentType instanceof Class)) { return new LateGenericArrayType(componentType); } } else if (clazz == Enum.class) { return Enum.class; // Special case: don't cook Enum class itself. Enum is silly. } else { // Cook generic classes (i.e., any class that has, or whose owner has, type parameters). Type ownerType = isInnerClass(clazz) ? apply(clazz.getEnclosingClass()) : clazz.getEnclosingClass(); TypeVariable[] typeParameters = clazz.getTypeParameters(); if (typeParameters.length > 0 || ownerType instanceof ParameterizedType) { return apply(new LateParameterizedType(clazz, ownerType, typeParameters)); } } return clazz; } @Override public Type apply(ParameterizedType pt) { Class rawType = erase(pt.getRawType()); Type[] typeArguments = pt.getActualTypeArguments(); return containsActiveVariable(typeArguments) ? // Check for cycles like "Enum>" rawType : new LateParameterizedType( rawType, isInnerClass(rawType) ? apply(pt.getOwnerType()) : pt.getOwnerType(), TypeTools.apply(this, typeArguments)); } @Override public Type apply(GenericArrayType gat) { return new LateGenericArrayType(apply(gat.getGenericComponentType())); } @Override public Type apply(WildcardType wt) { if (wt.getLowerBounds().length > 0) { Type[] lowerBounds = TypeTools.apply(this, wt.getLowerBounds()); return containsWildcard(lowerBounds) ? // Check for "? super ? extends Foo" new LateWildcardType("? super", erase(lowerBounds[0])) : new LateWildcardType("? super", lowerBounds); } else { Type[] upperBounds = TypeTools.apply(this, wt.getUpperBounds()); return containsWildcard(upperBounds) ? // Check for "? extends ? extends Foo" new LateWildcardType("? extends", erase(upperBounds[0])) : new LateWildcardType("? extends", upperBounds); } } @Override public Type apply(TypeVariable tv) { if (activeVariables.contains(tv)) { return erase(tv.getBounds()[0]); } activeVariables.add(tv); try { Type bound = apply(tv.getBounds()[0]); return bound instanceof WildcardType ? // Check for "? extends ? extends Foo" new LateWildcardType("? extends", erase(bound)) : new LateWildcardType("? extends", bound); } finally { activeVariables.remove(tv); } } private boolean containsActiveVariable(Type[] types) { for (Type type : types) { if (type instanceof TypeVariable && activeVariables.contains(type)) { return true; } } return false; } private static boolean containsWildcard(Type[] types) { for (Type type : types) { if (type instanceof WildcardType) { return true; } } return false; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy