/** * Copyright © 2006-2016 Web Cohesion (info@webcohesion.com) * * 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.webcohesion.enunciate.javac.decorations.type; import com.webcohesion.enunciate.javac.decorations.DecoratedProcessingEnvironment; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeParameterElement; import javax.lang.model.type.*; import java.util.Collection; import java.util.List; /** * @author Ryan Heaton */ public class TypeMirrorUtils { private static final String OBJECT_TYPE_PROPERTY = "com.webcohesion.enunciate.javac.decorations.type.TypeMirrorUtils#OBJECT_TYPE_PROPERTY"; private static final String COLLECTION_TYPE_PROPERTY = "com.webcohesion.enunciate.javac.decorations.type.TypeMirrorUtils#COLLECTION_TYPE_PROPERTY"; private static final String COLLECTION_TYPE_ERASURE_PROPERTY = "com.webcohesion.enunciate.javac.decorations.type.TypeMirrorUtils#COLLECTION_TYPE_ERASURE_PROPERTY"; private static final String LIST_TYPE_PROPERTY = "com.webcohesion.enunciate.javac.decorations.type.TypeMirrorUtils#LIST_TYPE_PROPERTY"; private static final String LIST_TYPE_ERASURE_PROPERTY = "com.webcohesion.enunciate.javac.decorations.type.TypeMirrorUtils#LIST_TYPE_ERASURE_PROPERTY"; private TypeMirrorUtils() {} public static DecoratedTypeMirror mirrorOf(Class<?> clazz, ProcessingEnvironment env) { if (clazz.isArray()) { return (DecoratedTypeMirror) env.getTypeUtils().getArrayType(mirrorOf(clazz.getComponentType(), env)); } else if (clazz.isPrimitive()) { return (DecoratedTypeMirror) env.getTypeUtils().getPrimitiveType(TypeKind.valueOf(clazz.getName().toUpperCase())); } else { TypeElement element = env.getElementUtils().getTypeElement(clazz.getCanonicalName()); if (element == null) { throw new IllegalStateException("Unable to find mirror for " + clazz.getCanonicalName()); } return (DecoratedTypeMirror) element.asType(); } } public static DecoratedTypeMirror mirrorOf(String typeName, DecoratedProcessingEnvironment env) { return mirrorOf(typeName, env, false); } public static DecoratedDeclaredType objectType(DecoratedProcessingEnvironment env) { DecoratedDeclaredType objectType = (DecoratedDeclaredType) env.getProperty(OBJECT_TYPE_PROPERTY); if (objectType == null) { objectType = (DecoratedDeclaredType) env.getElementUtils().getTypeElement(Object.class.getName()).asType(); env.setProperty(OBJECT_TYPE_PROPERTY, objectType); } return objectType; } public static DecoratedDeclaredType collectionType(DecoratedProcessingEnvironment env) { DecoratedDeclaredType collectionType = (DecoratedDeclaredType) env.getProperty(COLLECTION_TYPE_PROPERTY); if (collectionType == null) { collectionType = (DecoratedDeclaredType) env.getElementUtils().getTypeElement(Collection.class.getName()).asType(); env.setProperty(COLLECTION_TYPE_PROPERTY, collectionType); } return collectionType; } public static DecoratedDeclaredType collectionTypeErasure(DecoratedProcessingEnvironment env) { DecoratedDeclaredType collectionType = (DecoratedDeclaredType) env.getProperty(COLLECTION_TYPE_ERASURE_PROPERTY); if (collectionType == null) { collectionType = (DecoratedDeclaredType) env.getTypeUtils().erasure(collectionType(env)); env.setProperty(COLLECTION_TYPE_PROPERTY, collectionType); } return collectionType; } public static DecoratedDeclaredType listType(DecoratedProcessingEnvironment env) { DecoratedDeclaredType listType = (DecoratedDeclaredType) env.getProperty(LIST_TYPE_PROPERTY); if (listType == null) { listType = (DecoratedDeclaredType) env.getTypeUtils().erasure(env.getElementUtils().getTypeElement(List.class.getName()).asType()); env.setProperty(LIST_TYPE_PROPERTY, listType); } return listType; } public static DecoratedDeclaredType listTypeErasure(DecoratedProcessingEnvironment env) { DecoratedDeclaredType listType = (DecoratedDeclaredType) env.getProperty(LIST_TYPE_ERASURE_PROPERTY); if (listType == null) { listType = (DecoratedDeclaredType) env.getTypeUtils().erasure(listType(env)); env.setProperty(LIST_TYPE_PROPERTY, listType); } return listType; } public static TypeMirror resolveTypeVariable(TypeMirror typeVariable, List<? extends TypeParameterElement> elementParams, List<? extends TypeMirror> elementArgs) { if (typeVariable.getKind() == TypeKind.TYPEVAR) { int argIndex = -1; Name name = ((TypeVariable) typeVariable).asElement().getSimpleName(); for (int i = 0; i < elementParams.size(); i++) { TypeParameterElement elementParam = elementParams.get(i); if (elementParam.getSimpleName().equals(name)) { argIndex = i; break; } } if (argIndex < 0 || elementArgs.size() != elementParams.size()) { //best we can do is get the upper bound. should this maybe be an illegal state? typeVariable = ((TypeVariable) typeVariable).getUpperBound(); } else { typeVariable = elementArgs.get(argIndex); } } return typeVariable; } private static DecoratedTypeMirror mirrorOf(String typeName, DecoratedProcessingEnvironment env, boolean inArray) { DecoratedTypeMirror cached = (DecoratedTypeMirror) env.getProperty(mirrorKey(typeName)); if (cached != null) { return cached; } if (typeName.startsWith("[")) { return (DecoratedTypeMirror) env.getTypeUtils().getArrayType(mirrorOf(typeName.substring(1), env, true)); } else if (typeName.endsWith("[]")) { return (DecoratedTypeMirror) env.getTypeUtils().getArrayType(mirrorOf(typeName.substring(0, typeName.length() - 2), env, false)); } else if (inArray) { char firstChar = typeName.charAt(0); if (firstChar == 'L' && typeName.endsWith(";")) { return mirrorOf(typeName.substring(1, typeName.length() - 2), env, false); } switch (firstChar) { case 'Z': return (DecoratedTypeMirror) env.getTypeUtils().getPrimitiveType(TypeKind.BOOLEAN); case 'B': return (DecoratedTypeMirror) env.getTypeUtils().getPrimitiveType(TypeKind.BYTE); case 'C': return (DecoratedTypeMirror) env.getTypeUtils().getPrimitiveType(TypeKind.CHAR); case 'D': return (DecoratedTypeMirror) env.getTypeUtils().getPrimitiveType(TypeKind.DOUBLE); case 'F': return (DecoratedTypeMirror) env.getTypeUtils().getPrimitiveType(TypeKind.FLOAT); case 'I': return (DecoratedTypeMirror) env.getTypeUtils().getPrimitiveType(TypeKind.INT); case 'L': return (DecoratedTypeMirror) env.getTypeUtils().getPrimitiveType(TypeKind.LONG); case 'S': return (DecoratedTypeMirror) env.getTypeUtils().getPrimitiveType(TypeKind.SHORT); } } else { try { TypeKind kind = TypeKind.valueOf(typeName.toUpperCase()); if (kind.isPrimitive()) { return (DecoratedTypeMirror) env.getTypeUtils().getPrimitiveType(kind); } } catch (IllegalArgumentException e) { TypeElement element = env.getElementUtils().getTypeElement(typeName); if (element != null) { return (DecoratedTypeMirror) env.getTypeUtils().getDeclaredType(element); } } } return null; } private static String mirrorKey(String typeName) { return "com.webcohesion.enunciate.javac.decorations.type.TypeMirrorUtils#MIRROR_OF_" + typeName; } public static DecoratedTypeMirror getComponentType(DecoratedTypeMirror typeMirror, DecoratedProcessingEnvironment env) { if (typeMirror.isCollection()) { List<? extends TypeMirror> itemTypes = ((DeclaredType) typeMirror).getTypeArguments(); if (itemTypes.isEmpty()) { return objectType(env); } else { return (DecoratedTypeMirror) itemTypes.get(0); } } else if (typeMirror instanceof ArrayType) { return (DecoratedTypeMirror) ((ArrayType) typeMirror).getComponentType(); } return null; } }