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.
package com.hervian.lambda;
import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import org.paukov.combinatorics.Factory;
import org.paukov.combinatorics.Generator;
import org.paukov.combinatorics.ICombinatoricsVector;
/**
* Copyright 2016 Anders Granau Høfft
*
* 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.
* END OF NOTICE
*
* This AbstractProcessor only exists in order to auto-generate source code, namely an interface with multiple signatures.
* Since the processor is part of the project, where the annotation it processes i located, it is important the compilation
* proceeds in wel defined rounds, i.e. the processor must be compiled, before the annotated class, which triggers the processor.
* Being a Maven project, this is currently handled in the pom.xml file, by the maven-compiler-plugin.
*
* @author Anders Granau Høfft
*/
public class GenerateLambdaProcessor extends AbstractProcessor {
private static final String END_OF_SIGNATURE = ");";
private static final String NEWLINE_TAB = "\n\t";
private static final String NEWLINE = "\n";
private static final String INTERFACE_NAME = "Lambda";
private static final String PACKAGE = "com.hervian.lambda";
static final String METHOD_NAME = "invoke_for_";
private static final String METHOD_NAME_BOOLEAN = METHOD_NAME+boolean.class.getSimpleName();
private static final String METHOD_NAME_CHAR = METHOD_NAME+char.class.getSimpleName();
private static final String METHOD_NAME_BYTE = METHOD_NAME+byte.class.getSimpleName();
private static final String METHOD_NAME_SHORT = METHOD_NAME+short.class.getSimpleName();
private static final String METHOD_NAME_INT = METHOD_NAME+int.class.getSimpleName();
private static final String METHOD_NAME_FLOAT = METHOD_NAME+float.class.getSimpleName();
private static final String METHOD_NAME_LONG = METHOD_NAME+long.class.getSimpleName();
private static final String METHOD_NAME_DOUBLE = METHOD_NAME+double.class.getSimpleName();
private static final String METHOD_NAME_OBJECT = METHOD_NAME+Object.class.getSimpleName();
private static final String METHOD_NAME_VOID = METHOD_NAME+void.class.getSimpleName();
private static final String METHOD_NAME_PART_BOOLEAN = " "+METHOD_NAME_BOOLEAN +"(";
private static final String METHOD_NAME_PART_CHAR = " "+METHOD_NAME_CHAR +"(";
private static final String METHOD_NAME_PART_BYTE = " "+METHOD_NAME_BYTE +"(";
private static final String METHOD_NAME_PART_SHORT = " "+METHOD_NAME_SHORT +"(";
private static final String METHOD_NAME_PART_INT = " "+METHOD_NAME_INT +"(";
private static final String METHOD_NAME_PART_FLOAT = " "+METHOD_NAME_FLOAT +"(";
private static final String METHOD_NAME_PART_LONG = " "+METHOD_NAME_LONG +"(";
private static final String METHOD_NAME_PART_DOUBLE = " "+METHOD_NAME_DOUBLE +"(";
private static final String METHOD_NAME_PART_OBJECT = " "+METHOD_NAME_OBJECT +"(";
private static final String METHOD_NAME_PART_VOID = " "+METHOD_NAME_VOID +"(";
private Filer filer;
private static boolean fileCreated;
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public Set getSupportedAnnotationTypes() {
Set annotataions = new LinkedHashSet();
annotataions.add(GenerateLambda.class.getCanonicalName());
return annotataions;
}
@Override
public void init(ProcessingEnvironment processingEnv) {
filer = processingEnv.getFiler();
}
@Override
public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (!roundEnv.processingOver() && !fileCreated) {
Set extends Element> elements = roundEnv.getElementsAnnotatedWith(GenerateLambda.class);
for (Element element : elements) {
if (element.getKind() == ElementKind.CLASS) {
GenerateLambda generateSignatureContainerAnnotation = element.getAnnotation(GenerateLambda.class);
generateCode(PACKAGE, INTERFACE_NAME, generateSignatureContainerAnnotation);
return true;
}
break;
}
}
return true;
}
private void generateCode(String packageOfMarkerClass, String className, GenerateLambda generateSignatureContainerAnnotation) {
String fqcn = packageOfMarkerClass + "." + className;
try (Writer writer = filer.createSourceFile(fqcn).openWriter()) {
StringBuilder javaFile = new StringBuilder();
javaFile.append("package ").append(packageOfMarkerClass).append(";");
javaFile.append("\n\n/**\n * Copyright 2016 Anders Granau Høfft"
+ "\n * The invocation methods throws an AbstractMethodError, if arguments provided does not match "
+ "\n * the type defined by the Method over which the lambda was created."
+ "\n * A typical example of this is that the caller forget to cast a primitive number to its proper type. "
+ "\n * Fx. forgetting to explicitly cast a number as a short, byte etc. "
+ "\n * The AbstractMethodException will also be thrown if the caller does not provide"
+ "\n * an Object instance as the first argument to a non-static method, and vice versa."
+ "\n * @author Anders Granau Høfft").append("\n */")
.append("\[email protected](value=\"com.hervian.lambda.GenerateLambdaProcessor\", date=\"").append(new Date()).append("\")")
.append("\npublic interface " + className + "{\n");
generateAbstractandConcreteMethods(javaFile, generateSignatureContainerAnnotation);
javaFile.append("\n}");
writer.write(javaFile.toString());
fileCreated = true;
} catch (IOException e) {
throw new RuntimeException("An exception occurred while generating the source file "+METHOD_NAME, e);
}
}
private void generateAbstractandConcreteMethods(StringBuilder javaFile, GenerateLambda generateSignatureContainerAnnotation) {
MethodParameter[] types = generateSignatureContainerAnnotation.paramTypes();
int maxNumberOfParams = generateSignatureContainerAnnotation.maxNumberOfParameters();
generateAbstractMethods(javaFile, types, maxNumberOfParams);
}
private void generateAbstractMethods(StringBuilder javaFile, MethodParameter[] types, int maxNumberOfParams) {
List returnTypes = Arrays.asList(types).stream().map(type -> type.getTypeAsSourceCodeString()).collect(Collectors.toList());
returnTypes.add("void");
ICombinatoricsVector originalVector = Factory.createVector(types);
generateInterfaceMethodsForStaticCallsWithMaxNumOfArgs(javaFile, originalVector, returnTypes, maxNumberOfParams + 1);
generateInterfaceMethodCombinationsRecursively(javaFile, originalVector, returnTypes, maxNumberOfParams);
}
private void generateInterfaceMethodsForStaticCallsWithMaxNumOfArgs(StringBuilder javaFile,
ICombinatoricsVector originalVector, List returnTypes, int numberOfParams) {
Generator gen = Factory.createPermutationWithRepetitionGenerator(originalVector, numberOfParams);
for (String returnTypeAsString : returnTypes) {
for (ICombinatoricsVector paramType : gen) {
if (paramType.getVector().get(0) == MethodParameter.OBJECT) {
String parameters = getParametersString(paramType, javaFile);
javaFile.append(NEWLINE_TAB).append(returnTypeAsString).append(getSignatureExclArgsAndReturn(returnTypeAsString)).append(parameters).append(END_OF_SIGNATURE);
}
}
}
}
private void generateInterfaceMethodCombinationsRecursively(StringBuilder javaFile,
ICombinatoricsVector originalVector, List returnTypes, int numberOfParams) {
if (numberOfParams >= 0) {
javaFile.append(NEWLINE);
Generator gen = Factory.createPermutationWithRepetitionGenerator(originalVector, numberOfParams);
for (String returnTypeAsString : returnTypes) {
generateInterfaceMethods(gen, returnTypeAsString, javaFile);
}
generateInterfaceMethodCombinationsRecursively(javaFile, originalVector, returnTypes, --numberOfParams);
}
}
private void generateInterfaceMethods(Generator gen, String returnTypeAsString, StringBuilder javaFile) {
javaFile.append(NEWLINE);
for (ICombinatoricsVector paramType : gen) {
String parameters = getParametersString(paramType, javaFile);
javaFile.append(NEWLINE_TAB).append(returnTypeAsString).append(getSignatureExclArgsAndReturn(returnTypeAsString)).append(parameters).append(END_OF_SIGNATURE);
}
}
private String getParametersString(ICombinatoricsVector paramType, StringBuilder javaFile) {
AtomicInteger atomicInteger = new AtomicInteger(1);
return paramType.getVector().stream()
.map(t -> t.getTypeAsSourceCodeString() + " arg" + atomicInteger.getAndIncrement())
.collect(Collectors.joining(", "));
}
private static String getSignatureExclArgsAndReturn(String returnType){
switch (returnType){
case "boolean": return METHOD_NAME_PART_BOOLEAN;
case "byte": return METHOD_NAME_PART_BYTE;
case "char": return METHOD_NAME_PART_CHAR;
case "double": return METHOD_NAME_PART_DOUBLE;
case "float": return METHOD_NAME_PART_FLOAT;
case "int": return METHOD_NAME_PART_INT;
case "long": return METHOD_NAME_PART_LONG;
case "Object": return METHOD_NAME_PART_OBJECT;
case "short": return METHOD_NAME_PART_SHORT;
case "void" : return METHOD_NAME_PART_VOID;
default: return METHOD_NAME_PART_OBJECT;
}
}
static String getMethodName(String returnType){
switch (returnType){
case "boolean": return METHOD_NAME_BOOLEAN;
case "byte": return METHOD_NAME_BYTE;
case "char": return METHOD_NAME_CHAR;
case "double": return METHOD_NAME_DOUBLE;
case "float": return METHOD_NAME_FLOAT;
case "int": return METHOD_NAME_INT;
case "long": return METHOD_NAME_LONG;
case "Object": return METHOD_NAME_OBJECT;
case "short": return METHOD_NAME_SHORT;
case "void" : return METHOD_NAME_VOID;
default: return METHOD_NAME_OBJECT;
}
}
}