package io.vertx.codegen;

/*
 * Copyright 2014 Red Hat, Inc.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Apache License v2.0 which accompanies this distribution.
 *
 * The Eclipse Public License is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * The Apache License v2.0 is available at
 * http://www.opensource.org/licenses/apache2.0.php
 *
 * You may elect to redistribute this code under either of these licenses.
 */

import io.vertx.codegen.annotations.GenIgnore;
import io.vertx.codegen.type.ClassKind;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Author:Tim Fox
/** * @author <a href="http://tfox.org">Tim Fox</a> */
public class Helper { public static final Function<Element, Stream<ExecutableElement>> FILTER_METHOD = element -> { if (element.getKind() == ElementKind.METHOD) { return Stream.of((ExecutableElement) element); } else { return Stream.empty(); } }; public static final Function<Element, Stream<VariableElement>> FILTER_FIELD = element -> { if (element.getKind() == ElementKind.FIELD) { return Stream.of((VariableElement) element); } else { return Stream.empty(); } }; static <T> Function<Object, Stream<T>> instanceOf(Class<T> type) { return o -> { if (type.isInstance(o)) { return Stream.of(type.cast(o)); } else { return Stream.empty(); } }; } static <T> Function<Object, Stream<T>> cast(Class<T> type) { return o -> Stream.of(type.cast(o)); } static final Function<Element, Stream<ExecutableElement>> CAST = element -> { if (element.getKind() == ElementKind.METHOD) { return Stream.of((ExecutableElement) element); } else { return Stream.empty(); } };
Normalize a property name:
  • the first char will always be a lower case
  • if the first char is an upper case, any following upper case char will be lower cased unless it is followed by a lower case char
For instance:
  • foo -> foo
  • Foo -> foo
  • URL -> url
  • URLFactory -> urlFactory
Params:
  • propertyName – the property name
Returns:the normalized property name
/** * Normalize a property name:<br/> * * <ul> * <li>the first char will always be a lower case</li> * <li>if the first char is an upper case, any following upper case char will be lower cased unless it is followed * by a lower case char</li> * </ul> * * For instance: * <ul> * <li>foo -> foo</li> * <li>Foo -> foo</li> * <li>URL -> url</li> * <li>URLFactory -> urlFactory</li> * </ul> * * @param propertyName the property name * @return the normalized property name */
public static String normalizePropertyName(String propertyName) { if (Character.isUpperCase(propertyName.charAt(0))) { StringBuilder buffer = new StringBuilder(propertyName); int index = 0; while (true) { buffer.setCharAt(index, Character.toLowerCase(buffer.charAt(index++))); if (index < buffer.length() && Character.isUpperCase(buffer.charAt(index))) { if (index + 1 < buffer.length() && Character.isLowerCase(buffer.charAt(index + 1))) { break; } } else { break; } } propertyName = buffer.toString(); } return propertyName; } public static String decapitaliseFirstLetter(String str) { if (str.length() == 0) { return str; } else { return str.substring(0, 1).toLowerCase() + str.substring(1); } } public static String convertCamelCaseToUnderscores(String str) { return str.replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2").replaceAll("([a-z\\d])([A-Z])", "$1_$2").toLowerCase(); } public static String getSimpleName(String type) { return type.substring(type.lastIndexOf('.') + 1); } public static String getPackageName(String type) { int index = type.lastIndexOf('.'); if (index >= 0) { return type.substring(0, index); } else { return ""; } } public static String getNonGenericType(String type) { int pos = type.indexOf("<"); if (pos >= 0) { String nonGenericType = type.substring(0, pos); return nonGenericType; } else { return type; } } public static String indentString(String str, String indent) { StringBuilder sb = new StringBuilder(indent); for (int i = 0; i < str.length(); i++) { char ch = str.charAt(i); sb.append(ch); if (ch == '\n' && i != str.length() - 1) { sb.append(indent); } } return sb.toString(); } public static String getJavadocTag(String comment, String tagName) { int pos = comment.indexOf(tagName); int endPos = comment.indexOf("\n", pos); String tag = comment.substring(pos + tagName.length() + 1, endPos); return tag; } public static String removeTags(String comment) { // we remove everything from the first tag to the end of the comment - // tags MUST be at the end of the comment int pos = comment.indexOf('@'); if (pos == -1) { return comment; } if (pos > 0) { String beforePos = comment.substring(0, pos); int prevReturn = beforePos.lastIndexOf('\n'); if (prevReturn != -1) { pos = prevReturn; } else { pos = 0; } } return comment.substring(0, pos); }
Resolve a method annotation, this method scan the specified method, if the annotation is not found it will also scan the methods this method overrides and return the annotation when it is found.
Params:
  • annotationType – the annotation type,
  • elementUtils – element utils
  • typeUtils – type utils
  • declaring – the element declaring the method
  • method – the method to start the resolution from
Returns:the annotation if resolved otherwise null
/** * Resolve a method annotation, this method scan the specified method, if the annotation is not found * it will also scan the methods this method overrides and return the annotation when it is found. * * @param annotationType the annotation type, * @param elementUtils element utils * @param typeUtils type utils * @param declaring the element declaring the method * @param method the method to start the resolution from * @return the annotation if resolved otherwise null */
public static AnnotationMirror resolveMethodAnnotation( Class<? extends Annotation> annotationType, Elements elementUtils, Types typeUtils, TypeElement declaring, ExecutableElement method) { return resolveMethodAnnotation( (DeclaredType) elementUtils.getTypeElement(annotationType.getName()).asType(), elementUtils, typeUtils, declaring, method); }
Resolve a method annotation, this method scan the specified method, if the annotation is not found it will also scan the methods this method overrides and return the annotation when it is found.
Params:
  • annotationType – the annotation type,
  • elementUtils – element utils
  • typeUtils – type utils
  • declaring – the element declaring the method
  • method – the method to start the resolution from
Returns:the annotation if resolved otherwise null
/** * Resolve a method annotation, this method scan the specified method, if the annotation is not found * it will also scan the methods this method overrides and return the annotation when it is found. * * @param annotationType the annotation type, * @param elementUtils element utils * @param typeUtils type utils * @param declaring the element declaring the method * @param method the method to start the resolution from * @return the annotation if resolved otherwise null */
public static AnnotationMirror resolveMethodAnnotation( DeclaredType annotationType, Elements elementUtils, Types typeUtils, TypeElement declaring, ExecutableElement method) { Optional<? extends AnnotationMirror> annotation = method.getAnnotationMirrors().stream().filter(mirror -> typeUtils.isSameType(mirror.getAnnotationType(), annotationType)).findFirst(); if (annotation.isPresent()) { return annotation.get(); } else { return isFluent(annotationType, elementUtils, typeUtils, declaring, method, method.getEnclosingElement().asType()); } } private static AnnotationMirror isFluent(DeclaredType annotationType, Elements elementUtils, Types typeUtils, TypeElement declaring, ExecutableElement method, TypeMirror type) { for (TypeMirror directSuperType : typeUtils.directSupertypes(type)) { Element directSuperTypeElt = typeUtils.asElement(directSuperType); if (directSuperTypeElt instanceof TypeElement) { List<ExecutableElement> methods = ((TypeElement) directSuperTypeElt).getEnclosedElements().stream(). filter(member -> member.getKind() == ElementKind.METHOD).map(member -> (ExecutableElement) member). collect(Collectors.toList()); for (ExecutableElement m : methods) { if (elementUtils.overrides(method, m, declaring)) { AnnotationMirror annotation = resolveMethodAnnotation(annotationType, elementUtils, typeUtils, (TypeElement) directSuperTypeElt, m); if (annotation != null) { return annotation; } } } AnnotationMirror annotation = isFluent(annotationType, elementUtils, typeUtils, declaring, method, directSuperType); if (annotation != null) { return annotation; } } } return null; }
Return the type of a type parameter element of a given type element when that type parameter element is parameterized by a sub type, directly or indirectly. When the type parameter cannot be resolved, null is returned.
Params:
  • typeUtils – the type utils
  • subType – the sub type for which the type parameter is parameterized
  • typeParam – the type parameter to resolve
Returns:the type parameterizing the type parameter
/** * Return the type of a type parameter element of a given type element when that type parameter * element is parameterized by a sub type, directly or indirectly. When the type parameter cannot * be resolved, null is returned. * * @param typeUtils the type utils * @param subType the sub type for which the type parameter is parameterized * @param typeParam the type parameter to resolve * @return the type parameterizing the type parameter */
public static TypeMirror resolveTypeParameter(Types typeUtils, DeclaredType subType, TypeParameterElement typeParam) { TypeMirror erased = typeUtils.erasure(typeParam.getGenericElement().asType()); TypeMirror erasedSubType = typeUtils.erasure(subType); if (typeUtils.isSameType(erased, erasedSubType)) { return typeUtils.asMemberOf(subType, ((TypeVariable) typeParam.asType()).asElement()); } else if (typeUtils.isSubtype(erasedSubType, erased)) { for (TypeMirror superType : typeUtils.directSupertypes(subType)) { TypeMirror resolved = resolveTypeParameter(typeUtils, (DeclaredType) superType, typeParam); if (resolved != null) { return resolved; } } } return null; }
Return the type of a type parameter element of a given type element when that type parameter element is parameterized by a sub type, directly or indirectly. When the type parameter cannot be resolve, null is returned.
Params:
  • type – the sub type for which the type parameter is parameterized
  • typeParam – the type parameter to resolve
Returns:the type parameterizing the type parameter
/** * Return the type of a type parameter element of a given type element when that type parameter * element is parameterized by a sub type, directly or indirectly. When the type parameter cannot * be resolve, null is returned. * * @param type the sub type for which the type parameter is parameterized * @param typeParam the type parameter to resolve * @return the type parameterizing the type parameter */
public static <T> Type resolveTypeParameter(Type type, java.lang.reflect.TypeVariable<java.lang.Class<T>> typeParam) { if (type instanceof Class<?>) { Class<?> classType = (Class<?>) type; if (Stream.of(classType.getTypeParameters()).filter(tp -> tp.equals(typeParam)).findFirst().isPresent()) { return typeParam; } List<Type> superTypes = new ArrayList<>(); if (classType.getGenericSuperclass() != null) { superTypes.add(classType.getGenericSuperclass()); } Collections.addAll(superTypes, classType.getGenericInterfaces()); for (Type superType : superTypes) { Type resolved = resolveTypeParameter(superType, typeParam); if (resolved != null) { return resolved; } } } else if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; Type rawType = parameterizedType.getRawType(); Type resolvedType = resolveTypeParameter(rawType, typeParam); if (resolvedType instanceof java.lang.reflect.TypeVariable<?>) { GenericDeclaration owner = ((java.lang.reflect.TypeVariable) resolvedType).getGenericDeclaration(); if (owner.equals(rawType)) { java.lang.reflect.TypeVariable<?>[] typeParams = owner.getTypeParameters(); for (int i = 0;i < typeParams.length;i++) { if (typeParams[i].equals(resolvedType)) { return parameterizedType.getActualTypeArguments()[i]; } } } } } else { throw new UnsupportedOperationException("Todo " + type.getTypeName() + " " + type.getClass().getName()); } return null; } private static final Pattern SIGNATURE_PATTERN = Pattern.compile("#(\\p{javaJavaIdentifierStart}(?:\\p{javaJavaIdentifierPart})*)(?:\\((.*)\\))?$"); public static final Pattern LINK_REFERENCE_PATTERN = Pattern.compile( "(?:(?:\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*\\.)*" + "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)?" + "(?:" + SIGNATURE_PATTERN.pattern() + ")?");
Resolves a documentation signature, null can be returned if no element can be resolved.
Params:
  • elementUtils – the element utils
  • typeUtils – the type utils
  • declaringElt – the declaring element, may be null
  • signature – the signature to resolve
Returns:the resolved element
/** * Resolves a documentation signature, null can be returned if no element can be resolved. * * @param elementUtils the element utils * @param typeUtils the type utils * @param declaringElt the declaring element, may be null * @param signature the signature to resolve * @return the resolved element */
public static Element resolveSignature( Elements elementUtils, Types typeUtils, TypeElement declaringElt, String signature) { Matcher signatureMatcher = SIGNATURE_PATTERN.matcher(signature); if (signatureMatcher.find()) { String memberName = signatureMatcher.group(1); String typeName = signature.substring(0, signatureMatcher.start()); TypeElement typeElt = resolveTypeElement(elementUtils, declaringElt, typeName); if (typeElt != null) { Predicate<? super Element> memberMatcher; if (signatureMatcher.group(2) != null) { String t = signatureMatcher.group(2).trim(); Predicate<ExecutableElement> parametersMatcher; if (t.length() == 0) { parametersMatcher = exeElt -> exeElt.getParameters().isEmpty(); } else { parametersMatcher = parametersMatcher(typeUtils, t.split("\\s*,\\s*")); } memberMatcher = elt -> matchesConstructor(elt, memberName, parametersMatcher) || matchesMethod(elt, memberName, parametersMatcher); } else { memberMatcher = elt -> matchesConstructor(elt, memberName, exeElt -> true) || matchesMethod(elt, memberName, exeElt -> true) || matchesField(elt, memberName); } // The order of kinds is important for (ElementKind kind : Arrays.asList(ElementKind.FIELD, ElementKind.CONSTRUCTOR, ElementKind.METHOD)) { for (Element memberElt : elementUtils.getAllMembers(typeElt)) { if(memberElt.getKind() == kind && memberMatcher.test(memberElt)) { return memberElt; } } } } return null; } else { return resolveTypeElement(elementUtils, declaringElt, signature); } } private static TypeElement resolveTypeElement(Elements elementUtils, TypeElement declaringElt, String typeName) { TypeElement resolvedElt; if (typeName.isEmpty()) { resolvedElt = declaringElt; } else { if (typeName.lastIndexOf('.') == -1) { resolvedElt = elementUtils.getTypeElement("java.lang." +typeName); if (resolvedElt == null) { String packageName = elementUtils.getPackageOf(declaringElt).getQualifiedName().toString(); resolvedElt = elementUtils.getTypeElement(packageName + '.' + typeName); } } else { resolvedElt = elementUtils.getTypeElement(typeName); } } return resolvedElt; } private static boolean matchesConstructor(Element elt, String memberName, Predicate<ExecutableElement> parametersMatcher) { if (elt.getKind() == ElementKind.CONSTRUCTOR) { ExecutableElement constructorElt = (ExecutableElement) elt; TypeElement typeElt = (TypeElement) constructorElt.getEnclosingElement(); return typeElt.getSimpleName().toString().equals(memberName) && parametersMatcher.test(constructorElt); } return false; } private static boolean matchesMethod(Element elt, String memberName, Predicate<ExecutableElement> parametersMatcher) { if (elt.getKind() == ElementKind.METHOD) { ExecutableElement methodElt = (ExecutableElement) elt; return methodElt.getSimpleName().toString().equals(memberName) && parametersMatcher.test(methodElt); } return false; } private static boolean matchesField(Element elt, String memberName) { return elt.getKind() == ElementKind.FIELD && elt.getSimpleName().toString().equals(memberName); }
Return a matcher for parameters, given the parameter type signature of an executable element. The parameter signature is a list of parameter types formatted as a signature, i.e all types are raw, or primitive, or arrays. Unqualified types are resolved against the import of the specified compilationUnitTree argument.
Params:
  • parameterSignature – the parameter type names
Returns:the matcher
/** * Return a matcher for parameters, given the parameter type signature of an executable element. The parameter signature * is a list of parameter types formatted as a signature, i.e all types are raw, or primitive, or arrays. Unqualified * types are resolved against the import of the specified {@code compilationUnitTree} argument. * * @param parameterSignature the parameter type names * @return the matcher */
private static Predicate<ExecutableElement> parametersMatcher(Types typeUtils, String[] parameterSignature) { return exeElt -> { if (exeElt.getParameters().size() == parameterSignature.length) { TypeMirror tm2 = exeElt.asType(); ExecutableType tm3 = (ExecutableType) typeUtils.erasure(tm2); for (int j = 0; j < parameterSignature.length; j++) { String t1 = tm3.getParameterTypes().get(j).toString(); String t2 = parameterSignature[j]; if (t2.indexOf('.') == -1) { t1 = t1.substring(t1.lastIndexOf('.') + 1); } if (!t1.equals(t2)) { return false; } } return true; } else { return false; } }; }
Return the element type of the specified element.
Params:
  • elt – the element
Returns:the element type or null if none exists
/** * Return the element type of the specified element. * * @param elt the element * @return the element type or null if none exists */
public static TypeElement getElementTypeOf(Element elt) { ElementKind kind = elt.getKind(); if (kind == ElementKind.CLASS || kind == ElementKind.INTERFACE || kind == ElementKind.ENUM) { return (TypeElement) elt; } Element enclosingElt = elt.getEnclosingElement(); if (enclosingElt != null) { return getElementTypeOf(enclosingElt); } return null; } private static final Pattern WHITESPACE_CLUSTER_PATTERN = Pattern.compile("\\s+");
Trim and normalize the whitespaces in a string: any cluster of more than one whitespace char is replaced by a space char, then the string is trimmed.
Params:
  • s – the string to normalize
Returns:the normalized string
/** * Trim and normalize the whitespaces in a string: any cluster of more than one whitespace char * is replaced by a space char, then the string is trimmed. * * @param s the string to normalize * @return the normalized string */
public static String normalizeWhitespaces(String s) { Matcher matcher = WHITESPACE_CLUSTER_PATTERN.matcher(s); return matcher.replaceAll(" ").trim(); }
Resolve the set of all the ancestors declared types of a given type element.
Params:
  • typeElt – the type element to resolve
Returns:the set of ancestors
/** * Resolve the set of all the ancestors declared types of a given type element. * * @param typeElt the type element to resolve * @return the set of ancestors */
public static Set<DeclaredType> resolveAncestorTypes(TypeElement typeElt, boolean withSuper, boolean withInterfaces) { Set<DeclaredType> ancestors = new LinkedHashSet<>(); resolveAncestorTypes(typeElt, ancestors, withSuper, withInterfaces); return ancestors; } private static void resolveAncestorTypes(TypeElement typeElt, Set<DeclaredType> ancestors, boolean withSuper, boolean withInterfaces) { List<TypeMirror> superTypes = new ArrayList<>(); if (withSuper && typeElt.getSuperclass() != null) { superTypes.add(typeElt.getSuperclass()); } if (withInterfaces) { superTypes.addAll(typeElt.getInterfaces()); } for (TypeMirror superType : superTypes) { if (superType.getKind() == TypeKind.DECLARED) { DeclaredType superDeclaredType = (DeclaredType) superType; if (!ancestors.contains(superDeclaredType)) { ancestors.add(superDeclaredType); resolveAncestorTypes((TypeElement) superDeclaredType.asElement(), ancestors, withSuper, withInterfaces); } } } } static void checkUnderModule(Model model, String annotation) { if (model.getModule() == null) { throw new GenException(model.getElement(), "Declaration annotated with " + annotation + " must be under a package annotated" + "with @ModuleGen. Check that the package '" + model.getFqn() + "' or a parent package contains a 'package-info.java' using the @ModuleGen annotation"); } } static void ensureParentDir(File f) { if (!f.getParentFile().exists()) { f.getParentFile().mkdirs(); } }
Compute the string representation of a type mirror.
Params:
  • mirror – the type mirror
Returns:the string representation
/** * Compute the string representation of a type mirror. * * @param mirror the type mirror * @return the string representation */
static String toString(TypeMirror mirror) { StringBuilder buffer = new StringBuilder(); toString(mirror, buffer); return buffer.toString(); }
Compute the string representation of a type mirror.
Params:
  • mirror – the type mirror
  • buffer – the buffer appended with the string representation
/** * Compute the string representation of a type mirror. * * @param mirror the type mirror * @param buffer the buffer appended with the string representation */
static void toString(TypeMirror mirror, StringBuilder buffer) { switch (mirror.getKind()) { case DECLARED: { DeclaredType dt = (DeclaredType) mirror; TypeElement elt = (TypeElement) dt.asElement(); buffer.append(elt.getQualifiedName().toString()); List<? extends TypeMirror> args = dt.getTypeArguments(); if (args.size() > 0) { buffer.append("<"); for (int i = 0;i < args.size();i++) { if (i > 0) { buffer.append(","); } toString(args.get(i), buffer); } buffer.append(">"); } break; } case WILDCARD: { javax.lang.model.type.WildcardType wt = (javax.lang.model.type.WildcardType) mirror; buffer.append("?"); if (wt.getSuperBound() != null) { buffer.append(" super "); toString(wt.getSuperBound(), buffer); } else if (wt.getExtendsBound() != null) { buffer.append(" extends "); toString(wt.getExtendsBound(), buffer); } break; } case TYPEVAR: { javax.lang.model.type.TypeVariable tv = (TypeVariable) mirror; TypeParameterElement elt = (TypeParameterElement) tv.asElement(); buffer.append(elt.getSimpleName().toString()); if (tv.getUpperBound() != null && !tv.getUpperBound().toString().equals("java.lang.Object")) { buffer.append(" extends "); toString(tv.getUpperBound(), buffer); } else if (tv.getLowerBound() != null && tv.getLowerBound().getKind() != TypeKind.NULL) { buffer.append(" super "); toString(tv.getUpperBound(), buffer); } break; } case BYTE: case SHORT: case INT: case LONG: case FLOAT: case DOUBLE: case CHAR: case BOOLEAN: { PrimitiveType pm = (PrimitiveType) mirror; buffer.append(pm.getKind().name().toLowerCase()); break; } case ARRAY: { ArrayType at = (ArrayType) mirror; toString(at.getComponentType(), buffer); buffer.append("[]"); break; } default: throw new UnsupportedOperationException("todo " + mirror + " " + mirror.getKind()); } }
Like getReflectMethod(ClassLoader, ExecutableElement) but using the processing environment context.
/** * Like {@link #getReflectMethod(ClassLoader, ExecutableElement)} but using the processing environment context. */
public static Method getReflectMethod(ProcessingEnvironment env, ExecutableElement modelMethod) { ClassLoader loader = CodeGen.loaderMap.get(env); if (loader != null) { return getReflectMethod(loader, modelMethod); } return null; }
Returns a Method corresponding to the methodElt parameter. Obviously this work only when the corresponding method is available on the classpath using java lang reflection.
Params:
  • modelMethod – the model method element
Returns:the method or null if not found
/** * Returns a {@link Method } corresponding to the {@literal methodElt} parameter. Obviously this work * only when the corresponding method is available on the classpath using java lang reflection. * * @param modelMethod the model method element * @return the method or null if not found */
public static Method getReflectMethod(ClassLoader loader, ExecutableElement modelMethod) { TypeElement typeElt = (TypeElement) modelMethod.getEnclosingElement(); Method method = null; try { Class<?> clazz = loader.loadClass(typeElt.getQualifiedName().toString()); StringBuilder sb = new StringBuilder(modelMethod.getSimpleName()); sb.append("("); List<? extends VariableElement> params = modelMethod.getParameters(); for (int i = 0;i < params.size();i++) { if (i > 0) { sb.append(","); } VariableElement param = params.get(i); toString(param.asType(), sb); } sb.append(")"); String s = sb.toString(); for (Method m : clazz.getMethods()) { String sign = m.toGenericString(); int pos = sign.indexOf('('); pos = sign.lastIndexOf('.', pos) + 1; sign = sign.substring(pos); sign = sign.replace(", ", ","); // Remove space between arguments if (sign.equals(s)) { // Test this case if (method != null) { if (method.getReturnType().isAssignableFrom(m.getReturnType())) { method = m; } } else { method = m; } } } } catch (ClassNotFoundException e) { } return method; } public static ClassKind getAnnotatedDataObjectAnnotatedSerializationType(Elements elementUtils, TypeElement dataObjectElt) { return elementUtils.getAllMembers(dataObjectElt) .stream() .flatMap(Helper.FILTER_METHOD) .filter(exeElt -> exeElt.getParameters().isEmpty() && exeElt.getSimpleName().toString().equals("toJson")) .flatMap(exeElt -> { ClassKind ck; switch (exeElt.getReturnType().toString()) { case "io.vertx.core.json.JsonObject": return Stream.of(ClassKind.JSON_OBJECT); case "java.lang.String": return Stream.of(ClassKind.STRING); } return Stream.empty(); }) .findFirst() .orElse(null); } public static boolean isConcreteClass(TypeElement element) { return element.getKind() == ElementKind.CLASS && !element.getModifiers().contains(Modifier.ABSTRACT); } public static boolean isAbstractClassOrInterface(TypeElement element) { return element.getKind().isInterface() || (element.getKind() == ElementKind.CLASS && element.getModifiers().contains(Modifier.ABSTRACT)); } private static final Set<String> dataObjectTypes = new HashSet<>(Arrays.asList("io.vertx.core.json.JsonObject", "java.lang.String")); public static ClassKind getAnnotatedDataObjectDeserialisationType(Elements elementUtils, Types typeUtils, TypeElement dataObjectElt) { if (isConcreteClass(dataObjectElt)) { Set<String> types = elementUtils .getAllMembers(dataObjectElt) .stream() .filter(e -> e.getKind() == ElementKind.CONSTRUCTOR) .map(e -> (ExecutableElement) e) .filter(constructor -> constructor.getParameters().size() == 1 && constructor.getModifiers().contains(Modifier.PUBLIC) && dataObjectTypes.contains(constructor.getParameters().get(0).asType().toString())) .map(ctor -> ctor.getParameters().get(0).asType().toString()) .collect(Collectors.toSet()); // Order matter if (types.contains("io.vertx.core.json.JsonObject")) { return ClassKind.JSON_OBJECT; } else if (types.contains("java.lang.String")) { return ClassKind.STRING; } } return null; }
Params:
  • elt – the element to check
Returns:Return true if the elt is annotated with @GenIgnore.
/** * @param elt the element to check * @return Return {@code true} if the {@code elt} is annotated with {@code @GenIgnore}. */
public static boolean isGenIgnore(Element elt) { return elt.getAnnotation(GenIgnore.class) != null; } }