/** * Copyright 2015 Santhosh Kumar Tekuri * * The JLibs authors license this file to you 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 jlibs.core.lang.model; import jlibs.core.annotation.processing.AnnotationError; import jlibs.core.annotation.processing.Environment; import javax.lang.model.element.*; import javax.lang.model.type.ArrayType; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.tools.StandardLocation; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; /** * @author Santhosh Kumar T */ public class ModelUtil{ @SuppressWarnings({"unchecked"}) public static <T> T parent(Element element, Class<T> type){ do{ element = element.getEnclosingElement(); }while(!type.isInstance(element)); return (T)element; } public static TypeElement getSuper(TypeElement clazz){ TypeMirror superMirror = clazz.getSuperclass(); if(superMirror instanceof DeclaredType) return (TypeElement)((DeclaredType)superMirror).asElement(); else return null; } public static boolean isAssignable(TypeMirror type, Class clazz){ TypeMirror superType = Environment.get().getElementUtils().getTypeElement(clazz.getCanonicalName()).asType(); return Environment.get().getTypeUtils().isAssignable(type, superType); } public static String getPackage(Element elem){ while(!(elem instanceof PackageElement)) elem = elem.getEnclosingElement(); return ((PackageElement)elem).getQualifiedName().toString(); } public static boolean isInnerClass(TypeElement elem){ return !(elem.getEnclosingElement() instanceof PackageElement); } public static boolean isPrimitive(TypeMirror mirror){ switch(mirror.getKind()){ case ARRAY: case DECLARED: return false; default: return true; } } private static Map<String, String> primitiveWrappers = new HashMap<String, String>(); static{ primitiveWrappers.put(Boolean.class.getName(), boolean.class.getName()); primitiveWrappers.put(Byte.class.getName(), byte.class.getName()); primitiveWrappers.put(Short.class.getName(), short.class.getName()); primitiveWrappers.put(Integer.class.getName(), int.class.getName()); primitiveWrappers.put(Long.class.getName(), long.class.getName()); primitiveWrappers.put(Character.class.getName(), char.class.getName()); primitiveWrappers.put(Float.class.getName(), float.class.getName()); primitiveWrappers.put(Double.class.getName(), double.class.getName()); } public static boolean isPrimitiveWrapper(TypeMirror mirror){ return mirror.getKind()==TypeKind.DECLARED && primitiveWrappers.containsKey(toString(mirror, false)); } public static String getPrimitive(String primitiveWrapper){ return primitiveWrappers.get(primitiveWrapper); } public static String toString(TypeMirror mirror, boolean usePrimitiveWrappers){ TypeKind kind = mirror.getKind(); switch(kind){ case VOID: return "void"; case DECLARED: Name paramType = ((TypeElement)((DeclaredType)mirror).asElement()).getQualifiedName(); List<? extends TypeMirror> typeArguments = ((DeclaredType)mirror).getTypeArguments(); if(typeArguments.size()==0) return paramType.toString(); else{ StringBuilder buff = new StringBuilder(paramType).append('<'); for(TypeMirror typeArgument: typeArguments) buff.append(toString(typeArgument, false)); return buff.append('>').toString(); } case INT: return usePrimitiveWrappers ? Integer.class.getName() : kind.toString().toLowerCase(); case CHAR: return usePrimitiveWrappers ? Character.class.getName() : kind.toString().toLowerCase(); case BOOLEAN: case FLOAT: case DOUBLE: case LONG: case SHORT: case BYTE: String name = kind.toString().toLowerCase(); if(usePrimitiveWrappers) return "java.lang."+Character.toUpperCase(name.charAt(0))+name.substring(1); else return name; case ARRAY: return toString(((ArrayType)mirror).getComponentType(), false)+"[]"; default: throw new RuntimeException(kind +" is not implemented for "+mirror.getClass()); } } public static Modifier getModifier(Set<Modifier> set, Modifier... modifiers){ for(Modifier modifier: modifiers){ if(set.contains(modifier)) return modifier; } return null; } public static boolean isAccessible(Element element, boolean samePackage, boolean subClass){ Modifier modifier = getModifier(element.getModifiers(), Modifier.PUBLIC, Modifier.PROTECTED, Modifier.PRIVATE); if(modifier==null){ if(!samePackage) return false; }else{ switch(modifier){ case PRIVATE: return false; case PROTECTED: if(!samePackage && !subClass) return false; } } return true; } public static String signature(ExecutableElement method, boolean useParamNames){ StringBuilder buff = new StringBuilder(); Set<Modifier> modifiers = method.getModifiers(); Modifier modifier = getModifier(modifiers, Modifier.PUBLIC, Modifier.PROTECTED, Modifier.PRIVATE); if(modifier!=null) buff.append(modifier).append(' '); buff.append(toString(method.getReturnType(), false)); buff.append(' '); buff.append(method.getSimpleName()); buff.append('('); int i = 0; for(VariableElement param : method.getParameters()){ if(i>0) buff.append(", "); buff.append(toString(param.asType(), false)); if(useParamNames) buff.append(' ').append(param.getSimpleName()); i++; } buff.append(')'); List<? extends TypeMirror> throwTypes = method.getThrownTypes(); if(throwTypes.size()>0){ buff.append(" throws "); i = 0; for(TypeMirror throwType: throwTypes){ if(i>0) buff.append(", "); buff.append(throwType); i++; } } return buff.toString(); } public static VariableElement getParameter(ExecutableElement method, String paramName){ for(VariableElement param : method.getParameters()){ if(param.getSimpleName().contentEquals(paramName)) return param; } return null; } /*-------------------------------------------------[ Annotation ]---------------------------------------------------*/ public static boolean matches(AnnotationMirror mirror, Class annotation){ return ((TypeElement)mirror.getAnnotationType().asElement()).getQualifiedName().contentEquals(annotation.getCanonicalName()); } public static AnnotationMirror getAnnotationMirror(Element elem, Class annotation){ for(AnnotationMirror mirror: elem.getAnnotationMirrors()){ if(matches(mirror, annotation)) return mirror; } return null; } public static AnnotationValue getRawAnnotationValue(Element pos, AnnotationMirror mirror, String method){ for(Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : mirror.getElementValues().entrySet()){ if(entry.getKey().getSimpleName().contentEquals(method)) return entry.getValue(); } for(Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : Environment.get().getElementUtils().getElementValuesWithDefaults(mirror).entrySet()){ if(entry.getKey().getSimpleName().contentEquals(method)) return entry.getValue(); } throw new AnnotationError(pos, mirror, "annotation "+((TypeElement)mirror.getAnnotationType().asElement()).getQualifiedName()+" is missing "+method); } @SuppressWarnings({"unchecked"}) public static <T> T getAnnotationValue(Element pos, AnnotationMirror mirror, String method){ return (T)getRawAnnotationValue(pos, mirror, method).getValue(); } @SuppressWarnings("unchecked") public static <T> T getAnnotationValue(Element elem, Class annotation, String method){ AnnotationMirror mirror = getAnnotationMirror(elem, annotation); if(mirror!=null) return (T)getAnnotationValue(elem, mirror, method); else return null; } /*-------------------------------------------------[ javadoc ]---------------------------------------------------*/ private static final String PARAM = "@param"; private static final String RETURN = "@return"; public static String getMethodDoc(String doc){ if(doc==null) return null; else{ int index = doc.indexOf(PARAM); if(index==-1){ doc = doc.trim(); }else doc = doc.substring(0, index).trim(); index = doc.indexOf(RETURN); if(index==-1){ doc = doc.trim(); }else doc = doc.substring(0, index).trim(); return doc; } } private static String[] split(String str, boolean whitespace){ int i = 0; while(i<str.length()){ char ch = str.charAt(i); if(Character.isWhitespace(ch)==whitespace) i++; else break; } return new String[]{ str.substring(0, i), str.substring(i) }; } public static Map<String, String> getMethodParamDocs(String doc){ Map<String, String> docs = new HashMap<String, String>(); if(doc!=null){ int index = doc.indexOf(RETURN); if(index!=-1) doc = doc.substring(0, index); index = doc.indexOf(PARAM); if(index!=-1) doc = doc.substring(index).trim(); for(String token: doc.split(PARAM)){ token = token.trim(); if(token.length()>0){ String str[] = split(token, false); str[1] = str[1].trim(); if(str[0].length()>0 && str[1].length()>0) docs.put(str[0], str[1]); } } } return docs; } /*-------------------------------------------------[ Finding Generated Class ]---------------------------------------------------*/ public static String[] findClass(TypeElement clazz, String format){ String qname = format.replace("${package}", ModelUtil.getPackage(clazz)) .replace("${class}", clazz.getSimpleName().toString()); String pakage, clazzName; int dot = qname.lastIndexOf('.'); if(dot==-1){ pakage = ""; clazzName = qname; }else{ pakage = qname.substring(0, dot); clazzName = qname.substring(dot+1); if(pakage.length()==0) qname = clazzName; } return new String[]{ qname, pakage, clazzName }; } public static boolean exists(String pakage, String relativeName){ try{ InputStream is = null; try{ is = Environment.get().getFiler().getResource(StandardLocation.SOURCE_PATH, pakage, relativeName).openInputStream(); System.out.println("is: "+is); return true; }finally{ if(is!=null) is.close(); } }catch(Exception ignore){ return false; //http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6647998 } } }