All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.rapidpm.proxybuilder.core.annotationprocessor.BasicAnnotationProcessor Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses 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 org.rapidpm.proxybuilder.core.annotationprocessor;
import com.google.common.base.Joiner;
import com.squareup.javapoet.*;
import com.squareup.javapoet.TypeSpec.Builder;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Generated;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import static java.util.stream.Collectors.toList;
public abstract class BasicAnnotationProcessor extends AbstractProcessor {
public static final String METHOD_NAME_FINALIZE = "finalize";
public static final String METHOD_NAME_HASH_CODE = "hashCode";
public static final String METHOD_NAME_EQUALS = "equals";
protected static final String CLASS_NAME = "CLASS_NAME";
protected static final String DELEGATOR_FIELD_NAME = "delegator";
private final Set executableElementSet = new HashSet<>();
protected Filer filer;
protected Messager messager;
protected Elements elementUtils;
protected Types typeUtils;
protected Builder typeSpecBuilderForTargetClass;
@Override
public Set getSupportedAnnotationTypes() {
Set annotataions = new LinkedHashSet<>();
annotataions.add(responsibleFor().getCanonicalName());
return annotataions;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
typeUtils = processingEnv.getTypeUtils();
elementUtils = processingEnv.getElementUtils();
filer = processingEnv.getFiler();
messager = processingEnv.getMessager();
}
@Override
public boolean process(final Set annotations, final RoundEnvironment roundEnv) {
roundEnv
.getElementsAnnotatedWith(responsibleFor())
.stream()
.map(e -> (TypeElement) e)
.forEach(typeElement -> {
final TypeName interface2Implement = TypeName.get(typeElement.asType());
final Builder forTargetClass = createTypeSpecBuilderForTargetClass(typeElement, interface2Implement);
addClassLevelSpecs(typeElement, roundEnv);
System.out.println(" ============================================================ ");
executableElementSet.clear();
defineNewGeneratedMethod(typeElement, forTargetClass);
executableElementSet.clear();
System.out.println(" ============================================================ ");
writeDefinedClass(pkgName(typeElement), forTargetClass);
typeSpecBuilderForTargetClass = null;
});
return true;
}
public abstract Class responsibleFor();
private void defineNewGeneratedMethod(final TypeElement typeElement, final Builder forTargetClass) {
System.out.println("defineNewGeneratedMethod.typeElement = " + typeElement.getQualifiedName().toString());
if (typeElement == null) {
//loggen
} else {
// final Map> nativeNoneNativeMethodMap = typeElement
typeElement
.getEnclosedElements()
.stream()
.filter(e -> e.getKind() == ElementKind.METHOD)
.map(methodElement -> (ExecutableElement) methodElement) //cast only
.filter(methodElement -> methodElement.getModifiers().contains(Modifier.PUBLIC))
.filter(methodElement -> !methodElement.getModifiers().contains(Modifier.FINAL))
.filter(methodElement -> !methodElement.getSimpleName().toString().equals(METHOD_NAME_FINALIZE))
.filter(methodElement -> !executableElementSet.contains(new MethodIdentifier(methodElement)))
.forEach(
methodElement -> {
executableElementSet.add(new MethodIdentifier(methodElement));
final String methodName2Delegate = methodElement.getSimpleName().toString();
final CodeBlock codeBlock = defineMethodImplementation(methodElement, methodName2Delegate);
final MethodSpec delegatedMethodSpec = defineDelegatorMethod(methodElement, methodName2Delegate, codeBlock);
forTargetClass.addMethod(delegatedMethodSpec);
}
);
// .collect(Collectors.groupingBy(methodElement -> methodElement.getModifiers().contains(Modifier.NATIVE)));
// Optional - multipleMaps(MapStep... steps)
// filter
// NOW work on NON-native Methods
// if (nativeNoneNativeMethodMap.get(false) != null)
// nativeNoneNativeMethodMap
// .get(false)
// .forEach(
// methodElement -> {
// executableElementSet.add(new MethodIdentifier(methodElement));
// final String methodName2Delegate = methodElement.getSimpleName().toString();
// System.out.println("methodName2Delegate non-native = " + methodName2Delegate);
// final CodeBlock codeBlock = defineMethodImplementation(methodElement, methodName2Delegate);
//
// final MethodSpec delegatedMethodSpec = defineDelegatorMethod(methodElement, methodName2Delegate, codeBlock);
//
// forTargetClass.addMethod(delegatedMethodSpec);
// }
// );
//
// // NOW work on native Methods
// if (nativeNoneNativeMethodMap.get(true) != null)
// nativeNoneNativeMethodMap
// .get(true)
// .forEach(methodElement -> {
// executableElementSet.add(new MethodIdentifier(methodElement));
// final String methodName2Delegate = methodElement.getSimpleName().toString();
// System.out.println("methodName2Delegate native = " + methodName2Delegate);
// final CodeBlock codeBlock = defineMethodImplementation(methodElement, methodName2Delegate);
// final MethodSpec delegatedMethodSpec = defineDelegatorMethod(methodElement, methodName2Delegate, codeBlock);
// forTargetClass.addMethod(delegatedMethodSpec);
// });
// work on Parent class
final TypeMirror superclass = typeElement.getSuperclass();
if (superclass != null && !"none".equals(superclass.toString())) {
final TypeElement typeElement1 = (TypeElement) typeUtils.asElement(superclass);
defineNewGeneratedMethod(typeElement1, forTargetClass);
}
// work on Interfaces
typeElement.getInterfaces()
.stream()
.forEach(t -> defineNewGeneratedMethod((TypeElement) typeUtils.asElement(t), forTargetClass));
}
}
private Builder createTypeSpecBuilderForTargetClass(final TypeElement typeElement, final TypeName type2inherit) {
if (typeSpecBuilderForTargetClass == null) {
if (typeElement.getKind() == ElementKind.INTERFACE) {
typeSpecBuilderForTargetClass = TypeSpec
.classBuilder(targetClassNameSimple(typeElement))
.addSuperinterface(type2inherit);
} else if (typeElement.getKind() == ElementKind.CLASS) {
typeSpecBuilderForTargetClass = TypeSpec
.classBuilder(targetClassNameSimple(typeElement))
.superclass(type2inherit);
// .addModifiers(Modifier.PUBLIC);
} else {
throw new RuntimeException("alles doof");
}
typeElement.getModifiers()
.stream()
.filter(m -> !m.equals(Modifier.ABSTRACT))
.forEach(m -> typeSpecBuilderForTargetClass.addModifiers(m));
}
typeSpecBuilderForTargetClass.addAnnotation(createAnnotationSpecGenerated());
return typeSpecBuilderForTargetClass;
}
protected abstract void addClassLevelSpecs(final TypeElement typeElement, final RoundEnvironment roundEnv);
protected abstract CodeBlock defineMethodImplementation(final ExecutableElement methodElement, final String methodName2Delegate);
protected MethodSpec defineDelegatorMethod(final ExecutableElement methodElement, final String methodName2Delegate, final CodeBlock codeBlock) {
final Set reducedMethodModifiers = EnumSet.copyOf(methodElement.getModifiers());
reducedMethodModifiers.remove(Modifier.ABSTRACT);
reducedMethodModifiers.remove(Modifier.NATIVE);
return MethodSpec.methodBuilder(methodName2Delegate)
.addModifiers(reducedMethodModifiers)
.returns(TypeName.get(methodElement.getReturnType()))
.addParameters(defineParamsForMethod(methodElement))
.addExceptions(methodElement
.getThrownTypes()
.stream()
.map(TypeName::get)
.collect(toList()))
.addCode(codeBlock)
.build();
}
protected String targetClassNameSimple(final TypeElement typeElement) {
return ClassName.get(pkgName(typeElement), className(typeElement) + classNamePostFix()).simpleName();
}
private String classNamePostFix() {
return responsibleFor().getSimpleName();
}
protected Optional writeFunctionalInterface(ExecutableElement methodElement, MethodSpec.Builder methodSpecBuilder) {
final String methodNameRaw = methodElement.getSimpleName().toString();
final String firstCharUpper = (methodNameRaw.charAt(0) + "").toUpperCase();
final String finalMethodName = firstCharUpper + methodNameRaw.substring(1);
final Element typeElement = methodElement.getEnclosingElement();
final Builder functionalInterfaceTypeSpecBuilder = TypeSpec
.interfaceBuilder(typeElement.getSimpleName().toString() + "Method" + finalMethodName)
.addAnnotation(createAnnotationSpecGenerated())
.addAnnotation(FunctionalInterface.class)
.addMethod(methodSpecBuilder.build())
.addModifiers(Modifier.PUBLIC);
final Element enclosingElement = typeElement.getEnclosingElement();
final String packageName = enclosingElement.toString();
return writeDefinedClass(packageName, functionalInterfaceTypeSpecBuilder);
}
@NotNull
private AnnotationSpec createAnnotationSpecGenerated() {
return AnnotationSpec.builder(Generated.class)
.addMember("value", "$S", this.getClass().getSimpleName())
.addMember("date", "$S", LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME))
.addMember("comments", "$S", "www.proxybuilder.org")
.build();
}
protected Optional writeDefinedClass(String pkgName, Builder typeSpecBuilder) {
final TypeSpec typeSpec = typeSpecBuilder.build();
final JavaFile javaFile = JavaFile.builder(pkgName, typeSpec).skipJavaLangImports(true).build();
final String className = javaFile.packageName + "." + javaFile.typeSpec.name;
try {
JavaFileObject jfo = filer.createSourceFile(className);
Writer writer = jfo.openWriter();
javaFile.writeTo(writer);
writer.flush();
return Optional.of(typeSpec);
} catch (IOException e) {
e.printStackTrace();
if (e instanceof FilerException) {
if (e.getMessage().contains("Attempt to recreate a file for type")) {
return Optional.of(typeSpec);
}
}
System.out.println("e = " + e);
}
return Optional.empty();
}
protected FieldSpec defineSimpleClassNameField(final TypeElement typeElement) {
final ClassName className = ClassName.get(typeElement);
return FieldSpec
.builder(ClassName.get(String.class), CLASS_NAME)
.addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
// .initializer("\"" + className.simpleName() + "\"")
.initializer("\"" + className + "\"")
.build();
}
protected FieldSpec defineDelegatorField(final TypeElement typeElement) {
final ClassName delegatorClassName = ClassName.get(pkgName(typeElement), className(typeElement));
return FieldSpec
.builder(delegatorClassName, DELEGATOR_FIELD_NAME)
.addModifiers(Modifier.PRIVATE)
.build();
}
protected String pkgName(final TypeElement typeElement) {
return elementUtils.getPackageOf(typeElement).getQualifiedName().toString();
}
private String className(final Element typeElement) {
return typeElement.getSimpleName().toString();
}
protected String delegatorStatementWithReturn(final ExecutableElement methodElement, final String methodName2Delegate) {
return "return " + DELEGATOR_FIELD_NAME + "." + delegatorMethodCall(methodElement, methodName2Delegate);
}
protected String delegatorMethodCall(final ExecutableElement methodElement, final String methodName2Delegate) {
return methodName2Delegate + "(" +
Joiner.on(", ")
.skipNulls()
.join(defineParamsForMethod(methodElement)
.stream()
.map(v -> v.name)
.collect(toList())) +
")";
}
protected List defineParamsForMethod(final ExecutableElement methodElement) {
return methodElement
.getParameters()
.stream()
.map(parameter -> {
final Name simpleName = parameter.getSimpleName();
final TypeMirror typeMirror = parameter.asType();
TypeName typeName = TypeName.get(typeMirror);
return ParameterSpec.builder(typeName, simpleName.toString(), Modifier.FINAL).build();
})
.collect(toList());
}
private static class MethodIdentifier {
private final String name;
private final TypeName[] parameters;
public MethodIdentifier(final String name) {
this.name = name;
parameters = new TypeName[0];
}
public MethodIdentifier(final String name, TypeName... typeNames) {
this.name = name;
parameters = new TypeName[typeNames.length];
System.arraycopy(typeNames, 0, parameters, 0, parameters.length);
}
public MethodIdentifier(final ExecutableElement methodElement) {
final List p = methodElement.getParameters();
parameters = new TypeName[p.size()];
for (int i = 0; i < parameters.length; i++) {
final VariableElement variableElement = p.get(i);
parameters[i] = TypeName.get(variableElement.asType());
}
name = methodElement.getSimpleName().toString();
}
public int hashCode() {
return name.hashCode();
}
// we can save time by assuming that we only compare against
// other MethodIdentifier objects
public boolean equals(Object o) {
MethodIdentifier mid = (MethodIdentifier) o;
return name.equals(mid.name) &&
Arrays.equals(parameters, mid.parameters);
}
}
}