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

net.vvakame.apt.AptUtil Maven / Gradle / Ivy

/*
 * Copyright 2011 vvakame 
 *
 * 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.vvakame.apt;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ElementVisitor;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.NestingKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVisitor;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.SimpleElementVisitor6;
import javax.lang.model.util.SimpleTypeVisitor6;
import javax.lang.model.util.Types;

/**
 * Defines misc utils.
 * 
 * @author vvakame
 */
public class AptUtil {

	private AptUtil() {
	}

	/**
	 * Retrieves the super class of the given {@link Element}.
	 * Returns null if {@link Element} represents {@link Object}, or something other than {@link ElementKind#CLASS}.
	 * @param element target {@link Element}.
	 * @return {@link Element} of its super class.
	 * @author vvakame
	 */
	public static TypeElement getSuperClassElement(Element element) {
		if (element.getKind() != ElementKind.CLASS) {
			return null;
		}
		TypeMirror superclass = ((TypeElement) element).getSuperclass();
		if (superclass.getKind() == TypeKind.NONE) {
			return null;
		}
		DeclaredType kind = (DeclaredType) superclass;
		return (TypeElement) kind.asElement();
	}

	/**
	 * Tests if the given element is a kind of {@link Enum}.
	 * @param element
	 * @return true if the element passed is kind of {@link Enum}, false otherwise.
	 * @author vvakame
	 */
	public static boolean isEnum(Element element) {
		if (element == null) {
			return false;
		} else if (element.getKind() == ElementKind.ENUM) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Tests if the given element is a primitive wrapper.
	 * @param element
	 * @return true if the element is a primitive wrapper, false otherwise.
	 * @author vvakame
	 */
	public static boolean isPrimitiveWrapper(Element element) {
		if (element == null) {
			return false;
		} else if (element.toString().equals(Boolean.class.getCanonicalName())) {
			return true;
		} else if (element.toString().equals(Integer.class.getCanonicalName())) {
			return true;
		} else if (element.toString().equals(Long.class.getCanonicalName())) {
			return true;
		} else if (element.toString().equals(Byte.class.getCanonicalName())) {
			return true;
		} else if (element.toString().equals(Short.class.getCanonicalName())) {
			return true;
		} else if (element.toString().equals(Character.class.getCanonicalName())) {
			return true;
		} else if (element.toString().equals(Double.class.getCanonicalName())) {
			return true;
		} else if (element.toString().equals(Float.class.getCanonicalName())) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Test if the given element is primitive boolean.
	 * @param element
	 * @return True if the type is a primitive boolean. false otherwise.
	 * @author vvakame
	 */
	public static boolean isPrimitiveBoolean(Element element) {
		return "boolean".equals(element.asType().toString());
	}

	/**
	 * Test if the given type is an internal type.
	 * @param typeUtils
	 * @param type
	 * @return True if the type is an internal type, false otherwise.
	 * @author vvakame
	 */
	public static boolean isInternalType(Types typeUtils, TypeMirror type) {
		Element element = ((TypeElement) typeUtils.asElement(type)).getEnclosingElement();
		return element.getKind() != ElementKind.PACKAGE;
	}

	/**
	 * Retrieves the corresponding {@link TypeElement} of the given element.
	 * @param typeUtils
	 * @param element
	 * @return The corresponding {@link TypeElement}.
	 * @author vvakame
	 */
	public static TypeElement getTypeElement(Types typeUtils, Element element) {
		TypeMirror type = element.asType();
		return (TypeElement) typeUtils.asElement(type);
	}

	/**	 
	 * Retrieves {@link Element}s matching the given annoation and kind (only if given,) from children of the given root.
	 * @param parent The element search from.
	 * @param annotation Annotation looking for
	 * @param kind {@link ElementKind} looking for
	 * @return {@link Element}s matched
	 * @author vvakame
	 */
	public static List getEnclosedElementsByAnnotation(Element parent,
			Class annotation, ElementKind kind) {
		List elements = parent.getEnclosedElements();
		List results = new ArrayList();

		for (Element element : elements) {
			if (kind != null && element.getKind() != kind) {
				continue;
			}
			Object key = element.getAnnotation(annotation);
			if (key == null) {
				continue;
			}
			results.add(element);
		}

		return results;
	}

	/**
	 * Returns the package name of the given element.
	 * NB: This method requires the given element has the kind of {@link ElementKind#CLASS}.
	 * @param elementUtils 
	 * @param element
	 * @return the package name
	 * @author vvakame
	 */
	public static String getPackageName(Elements elementUtils, Element element) {
		return elementUtils.getPackageOf(element).getQualifiedName().toString();
	}

	/**
	 * Returns the package name of the given {@link TypeMirror}.
	 * @param elementUtils 
	 * @param typeUtils 
	 * @param type 
	 * @return the package name
	 * @author backpaper0
	 * @author vvakame
	 */
	public static String getPackageName(Elements elementUtils, Types typeUtils, TypeMirror type) {
		TypeVisitor tv = new SimpleTypeVisitor6() {

			@Override
			public DeclaredType visitDeclared(DeclaredType t, Object p) {
				return t;
			}
		};
		DeclaredType dt = type.accept(tv, null);
		if (dt != null) {
			ElementVisitor ev =
					new SimpleElementVisitor6() {

						@Override
						public TypeElement visitType(TypeElement e, Object p) {
							return e;
						}
					};
			TypeElement el = typeUtils.asElement(dt).accept(ev, null);
			if (el != null && el.getNestingKind() != NestingKind.TOP_LEVEL) {
				return AptUtil.getPackageName(elementUtils, el);
			}
		}
		return AptUtil.getPackageNameSub(type);
	}

	private static String getPackageNameSub(TypeMirror type) {
		String s = type.toString();
		return s.substring(0, s.lastIndexOf('.'));
	}

	/**
	 * Returns unqualified class name (e.g. String, if java.lang.String)
	 * NB: This method requires the given element has the kind of {@link ElementKind#CLASS}.
	 * @param element
	 * @return unqualified class name
	 * @author vvakame
	 */
	public static String getSimpleName(Element element) {
		if (element.getKind() != ElementKind.CLASS) {
			throw new IllegalStateException();
		}
		String str = element.asType().toString();
		int i = str.lastIndexOf(".");
		return str.substring(i + 1);
	}

	/**
	 * Returns unqualified class name (e.g. String, if java.lang.String)
	 * NB: This method requires the given element has the kind of {@link ElementKind#CLASS}.
	 * @param element
	 * @return unqualified class name
	 * @author vvakame
	 */
	public static String getNameForNew(Element element) {
		if (element.getKind() != ElementKind.CLASS) {
			throw new IllegalStateException();
		}
		return getNameForNew("", element);
	}

	static String getNameForNew(String current, Element element) {
		if (element.getKind() == ElementKind.PACKAGE) {
			return current;
		} else {
			String str = element.asType().toString();
			int i = str.lastIndexOf(".");
			String now = str.substring(i + 1);
			if ("".equals(current)) {
				return getNameForNew(now, element.getEnclosingElement());
			} else {
				return getNameForNew(now + "." + current, element.getEnclosingElement());
			}
		}
	}

	/**
	 * Returns unqualified class name (e.g. String, if java.lang.String)
	 * NB: This method requires the given element has the kind of {@link ElementKind#CLASS}.
	 * @param tm
	 * @return unqualified class name
	 * @author vvakame
	 */
	public static String getSimpleName(TypeMirror tm) {
		String str = tm.toString();
		int i = str.lastIndexOf(".");
		return str.substring(i + 1);
	}

	/**
	 * Returns the fully qualified name.
	 * @param tm
	 * @return The fully qualified name
	 * @author vvakame
	 */
	public static String getFullQualifiedName(TypeMirror tm) {
		String str = tm.toString();
		int i = str.lastIndexOf("<");
		if (0 < i) {
			return str.substring(i + 1);
		} else {
			return str;
		}
	}

	/**
	 * Returns the fully qualified name.
	 * @param element
	 * @return The fully qualified name
	 * @author vvakame
	 */
	public static String getFullQualifiedName(Element element) {
		return element.toString();
	}

	static boolean checkModifier(Element element, Modifier modifier) {
		for (Modifier m : element.getModifiers()) {
			if (modifier == m) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Tests if the given element has the public visibility.
	 * @param element
	 * @return true if public, false otherwise
	 * @author vvakame
	 */
	public static boolean isPublic(Element element) {
		return checkModifier(element, Modifier.PUBLIC);
	}

	/**
	 * Tests if the given element has the protected visibility.
	 * @param element
	 * @return true if protected, false otherwise
	 * @author vvakame
	 */
	public static boolean isProtected(Element element) {
		return checkModifier(element, Modifier.PROTECTED);
	}

	/**
	 * Tests if the given element has the private visibility.
	 * @param element
	 * @return true if private, false otherwise
	 * @author vvakame
	 */
	public static boolean isPrivate(Element element) {
		return checkModifier(element, Modifier.PRIVATE);
	}

	/**
	 * Tests if the given element has the package-private visibility.
	 * @param element
	 * @return true if package-private, false otherwise
	 * @author vvakame
	 */
	public static boolean isPackagePrivate(Element element) {
		if (isPublic(element)) {
			return false;
		} else if (isProtected(element)) {
			return false;
		} else if (isPrivate(element)) {
			return false;
		}
		return true;
	}

	/**
	 * Tests if the given element has static scope.
	 * @param element
	 * @return true if static, false otherwise
	 * @author vvakame
	 */
	public static boolean isStatic(Element element) {
		return checkModifier(element, Modifier.STATIC);
	}

	/**
	 * Tests if the given element has the method with the given name.
* NB: This method requires the given element has the kind of {@link ElementKind#CLASS}.
* Also tests the method qualifies all of modifiers if any {@link Modifier} are also given. * @param element * @param methodName * @param modifiers * @return true if a match is found, false otherwise * @author vvakame */ public static boolean isMethodExists(Element element, String methodName, Modifier... modifiers) { if (element.getKind() != ElementKind.CLASS) { throw new IllegalStateException(); } List modifiersList = Arrays.asList(modifiers); List methods = ElementFilter.methodsIn(element.getEnclosedElements()); for (ExecutableElement method : methods) { if (method.getSimpleName().toString().equals(methodName) && method.getModifiers().containsAll(modifiersList)) { return true; } } return false; } static String cutAfterString(String base, char key) { if (base == null) { return null; } int lastIndexOf = base.lastIndexOf(key); if (lastIndexOf < 0) { return base; } else { return base.substring(0, lastIndexOf); } } /** * Returns the name of corresponding setter. * @param element the field * @return setter name * @author vvakame */ public static String getElementSetter(Element element) { // 後続処理注意 hogeに対して sethoge が取得される. setHoge ではない. String setterName = null; if (isPrimitiveBoolean(element)) { Pattern pattern = Pattern.compile("^is[^a-z].*$"); Matcher matcher = pattern.matcher(element.getSimpleName().toString()); if (matcher.matches()) { // boolean isHoge; に対して setIsHoge ではなく setHoge が生成される setterName = "set" + element.getSimpleName().toString().substring(2); } } if (setterName == null) { setterName = "set" + element.getSimpleName().toString(); } Element setter = null; for (Element method : ElementFilter.methodsIn(element.getEnclosingElement() .getEnclosedElements())) { String methodName = method.getSimpleName().toString(); if (setterName.equalsIgnoreCase(methodName)) { if (isStatic(method) == false && isPublic(method) || isPackagePrivate(method)) { setter = method; break; } } } if (setter != null) { return setter.getSimpleName().toString(); } else { return null; } } /** * Returns the name of corresponding getter. * @param element the field * @return getter name * @author vvakame */ public static String getElementGetter(Element element) { // TODO 型(boolean)による絞り込みをするべき String getterName1 = "get" + element.getSimpleName().toString(); String getterName2 = "is" + element.getSimpleName().toString(); String getterName3 = element.getSimpleName().toString(); Element getter = null; for (Element method : ElementFilter.methodsIn(element.getEnclosingElement() .getEnclosedElements())) { String methodName = method.getSimpleName().toString(); if (getterName1.equalsIgnoreCase(methodName)) { if (isStatic(method) == false && isPublic(method) || isPackagePrivate(method)) { getter = method; break; } } else if (getterName2.equalsIgnoreCase(methodName)) { if (isStatic(method) == false && isPublic(method) || isPackagePrivate(method)) { getter = method; break; } } else if (getterName3.equalsIgnoreCase(methodName)) { if (isStatic(method) == false && isPublic(method) || isPackagePrivate(method)) { getter = method; break; } } } if (getter != null) { return getter.getSimpleName().toString(); } else { return null; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy