diff --git a/src/de/steamwar/linkage/LinkageProcessor.java b/src/de/steamwar/linkage/LinkageProcessor.java index 70253df..7965140 100644 --- a/src/de/steamwar/linkage/LinkageProcessor.java +++ b/src/de/steamwar/linkage/LinkageProcessor.java @@ -23,6 +23,7 @@ import de.steamwar.linkage.plan.BuildPlan; import de.steamwar.linkage.plan.FieldBuilder; import de.steamwar.linkage.plan.MethodBuilder; import de.steamwar.linkage.types.Plain_GENERIC; +import lombok.Cleanup; import lombok.Getter; import lombok.SneakyThrows; @@ -42,6 +43,7 @@ import java.nio.file.Path; import java.util.*; import java.util.function.Consumer; import java.util.stream.Collectors; +import java.util.stream.Stream; @SupportedAnnotationTypes("de.steamwar.linkage.Linked") public class LinkageProcessor extends AbstractProcessor { @@ -52,7 +54,6 @@ public class LinkageProcessor extends AbstractProcessor { private static String pluginMain; private String name; - private String packageName; private String className; private Messager messager; @@ -72,7 +73,6 @@ public class LinkageProcessor extends AbstractProcessor { messager = processingEnv.getMessager(); - packageName = "de.steamwar." + name + ".linkage"; className = "LinkageUtils"; mainClass(); } @@ -90,22 +90,15 @@ public class LinkageProcessor extends AbstractProcessor { return; } context = pluginYMLFile.get().getName().equals("bungee.yml") ? Context.BUNGEE : Context.SPIGOT; - Optional mainName = getMainName(pluginYMLFile.get()); - if (!mainName.isPresent()) { + @Cleanup BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(pluginYMLFile.get()))); + Optional mainName = reader.lines() + .filter(line -> line.startsWith("main:")) + .map(line -> line.substring(line.indexOf(':') + 1).trim()) + .findFirst(); + if (mainName.isPresent()) { + pluginMain = mainName.get(); + } else { messager.printMessage(Diagnostic.Kind.ERROR, "Could not find main class in plugin.yml or bungee.yml"); - return; - } - pluginMain = mainName.get(); - } - - @SneakyThrows - private Optional getMainName(File pluginYML) { - if (!pluginYML.exists()) return Optional.empty(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(pluginYML)))) { - return reader.lines() - .filter(line -> line.startsWith("main:")) - .map(line -> line.substring(line.indexOf(':') + 1).trim()) - .findFirst(); } } @@ -116,14 +109,17 @@ public class LinkageProcessor extends AbstractProcessor { processed = true; Writer writer = processingEnv.getFiler().createSourceFile("de.steamwar." + name + ".linkage.LinkageUtils").openWriter(); - - BuildPlan buildPlan = new BuildPlan(packageName, className); + BuildPlan buildPlan = new BuildPlan("de.steamwar." + name + ".linkage", className); Set elements = roundEnv.getElementsAnnotatedWith(Linked.class).stream() .filter(element -> element.getKind() == ElementKind.CLASS) .map(TypeElement.class::cast) + .peek(typeElement -> System.out.println("Found element: " + typeElement.getQualifiedName().toString())) .collect(Collectors.toSet()); + Map, List> groupedByChecks = elements.stream() + .collect(Collectors.groupingBy(element -> checks(element, buildPlan))); + Map neededFields = new HashMap<>(); Set fieldInjections = new HashSet<>(); for (TypeElement typeElement : elements) { @@ -136,9 +132,7 @@ public class LinkageProcessor extends AbstractProcessor { .map(VariableElement.class::cast) .filter(e -> e.getAnnotation(LinkedInstance.class) != null) .collect(Collectors.toList()); - if (variableElements.isEmpty()) { - continue; - } + if (variableElements.isEmpty()) continue; for (VariableElement variableElement : variableElements) { if (!variableElement.getModifiers().contains(Modifier.PUBLIC)) { @@ -178,25 +172,33 @@ public class LinkageProcessor extends AbstractProcessor { fieldInjections.forEach(Runnable::run); Map methods = new HashMap<>(); - for (TypeElement typeElement : elements) { - System.out.println("Found element: " + typeElement.getQualifiedName().toString()); - Map> linkages = getLinkagesOfType(typeElement); - if (linkages.isEmpty()) { - continue; + for (Map.Entry, List> entry : groupedByChecks.entrySet()) { + Map>> groupedByMethod = new HashMap<>(); + for (TypeElement typeElement : entry.getValue()) { + for (Map.Entry> linkages : getLinkagesOfType(typeElement).entrySet()) { + Map> internalGroup = groupedByMethod.computeIfAbsent(linkages.getKey(), s -> new HashMap<>()); + for (LinkageType linkageType : linkages.getValue()) { + List list = internalGroup.computeIfAbsent(linkageType, s -> new ArrayList<>()); + list.add(typeElement); + } + } } - for (Map.Entry> entry : linkages.entrySet()) { - MethodBuilder method = methods.computeIfAbsent(entry.getKey(), s -> { + for (Map.Entry>> group : groupedByMethod.entrySet()) { + MethodBuilder method = methods.computeIfAbsent(group.getKey(), s -> { MethodBuilder methodBuilder = new MethodBuilder(s, "void"); buildPlan.addMethod(methodBuilder); return methodBuilder; }); - for (LinkageType type : entry.getValue()) { - specialElements(typeElement, buildPlan, method::addLine, () -> { + + if (!entry.getKey().isEmpty()) method.addLine("if (" + String.join(" && ", entry.getKey()) + ") {"); + for (Map.Entry> toGenerate : group.getValue().entrySet()) { + toGenerate.getValue().forEach(typeElement -> { buildPlan.addImport(typeElement.getQualifiedName().toString()); - type.generateCode(buildPlan, method, getElement(typeElement, neededFields), typeElement); + toGenerate.getKey().generateCode(buildPlan, method, getElement(typeElement, neededFields), typeElement); }); } + if (!entry.getKey().isEmpty()) method.addLine("}"); } } @@ -214,14 +216,14 @@ public class LinkageProcessor extends AbstractProcessor { return "new " + s + "()"; } - private void specialElements(TypeElement typeElement, BuildPlan buildPlan, Consumer stringConsumer, Runnable inner) { + private Set checks(TypeElement typeElement, BuildPlan buildPlan) { + Set checks = new HashSet<>(); MinVersion minVersion = typeElement.getAnnotation(MinVersion.class); MaxVersion maxVersion = typeElement.getAnnotation(MaxVersion.class); EventMode eventMode = typeElement.getAnnotation(EventMode.class); PluginCheck[] pluginChecks = typeElement.getAnnotationsByType(PluginCheck.class); if (context == Context.SPIGOT) { errorOnNonNull(typeElement, eventMode); - List checks = new ArrayList<>(); if (minVersion != null) { buildPlan.addImport("de.steamwar.core.Core"); checks.add("Core.getVersion() >= " + minVersion.value()); @@ -236,12 +238,8 @@ public class LinkageProcessor extends AbstractProcessor { return "Bukkit.getPluginManager().getPlugin(\"" + pluginCheck.value() + "\") " + (pluginCheck.has() == PluginCheck.Has.THIS ? "!" : "=") + "= null"; }).forEach(checks::add); } - if (!checks.isEmpty()) stringConsumer.accept("if (" + String.join(" && ", checks) + ") {"); - inner.run(); - if (!checks.isEmpty()) stringConsumer.accept("}"); } else { errorOnNonNull(typeElement, minVersion, maxVersion); - List checks = new ArrayList<>(); if (eventMode != null) { buildPlan.addImport("de.steamwar.bungeecore.BungeeCore"); checks.add(eventMode.value().getPrefix() + "BungeeCore.EVENT_MODE"); @@ -252,10 +250,15 @@ public class LinkageProcessor extends AbstractProcessor { return "BungeeCord.getPluginManager().getPlugin(\"" + pluginCheck.value() + "\") " + (pluginCheck.has() == PluginCheck.Has.THIS ? "!" : "=") + "= null"; }).forEach(checks::add); } - if (!checks.isEmpty()) stringConsumer.accept("if (" + String.join(" && ", checks) + ") {"); - inner.run(); - if (!checks.isEmpty()) stringConsumer.accept("}"); } + return checks; + } + + private void specialElements(TypeElement typeElement, BuildPlan buildPlan, Consumer stringConsumer, Runnable inner) { + Set checks = checks(typeElement, buildPlan); + if (!checks.isEmpty()) stringConsumer.accept("if (" + String.join(" && ", checks) + ") {"); + inner.run(); + if (!checks.isEmpty()) stringConsumer.accept("}"); } private void errorOnNonNull(TypeElement typeElement, Annotation... annotations) { @@ -270,16 +273,10 @@ public class LinkageProcessor extends AbstractProcessor { private Map> getLinkagesOfType(TypeElement typeElement) { Map> linkages = new HashMap<>(); - LinkageType superClassType = resolveSingle(typeElement.getSuperclass()); - if (superClassType != null) { - linkages.computeIfAbsent(superClassType.method(), s -> new ArrayList<>()).add(superClassType); - } - for (TypeMirror typeMirror : typeElement.getInterfaces()) { - LinkageType interfaceType = resolveSingle(typeMirror); - if (interfaceType != null) { - linkages.computeIfAbsent(interfaceType.method(), s -> new ArrayList<>()).add(interfaceType); - } - } + Stream.concat(Stream.of(typeElement.getSuperclass()), typeElement.getInterfaces().stream()) + .map(this::resolveSingle) + .filter(Objects::nonNull) + .forEach(linkageType -> linkages.computeIfAbsent(linkageType.method(), s -> new ArrayList<>()).add(linkageType)); if (linkages.size() == 1 && linkages.containsKey("unlink")) { linkages.put(plain_GENERIC.method(), Collections.singletonList(plain_GENERIC)); }