Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-16 21:10:30 +01:00
Add annotation processor for @Subscribe
Dieser Commit ist enthalten in:
Ursprung
e6e35d3754
Commit
ee2870aafb
@ -0,0 +1,8 @@
|
|||||||
|
package com.velocitypowered.annotationprocessor;
|
||||||
|
|
||||||
|
class AnnotationProcessorConstants {
|
||||||
|
|
||||||
|
static final String PLUGIN_ANNOTATION_CLASS = "com.velocitypowered.api.plugin.Plugin";
|
||||||
|
static final String SUBSCRIBE_ANNOTATION_CLASS = "com.velocitypowered.api.event.Subscribe";
|
||||||
|
static final String EVENTTASK_CLASS = "com.velocitypowered.api.event.EventTask";
|
||||||
|
}
|
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Velocity Contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.velocitypowered.annotationprocessor;
|
||||||
|
|
||||||
|
import static com.velocitypowered.annotationprocessor.AnnotationProcessorConstants.EVENTTASK_CLASS;
|
||||||
|
import static com.velocitypowered.annotationprocessor.AnnotationProcessorConstants.PLUGIN_ANNOTATION_CLASS;
|
||||||
|
import static com.velocitypowered.annotationprocessor.AnnotationProcessorConstants.SUBSCRIBE_ANNOTATION_CLASS;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
|
import com.velocitypowered.api.plugin.Plugin;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.processing.AbstractProcessor;
|
||||||
|
import javax.annotation.processing.Messager;
|
||||||
|
import javax.annotation.processing.ProcessingEnvironment;
|
||||||
|
import javax.annotation.processing.RoundEnvironment;
|
||||||
|
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||||
|
import javax.lang.model.SourceVersion;
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.element.ElementKind;
|
||||||
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
import javax.lang.model.element.Modifier;
|
||||||
|
import javax.lang.model.element.Name;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.lang.model.element.VariableElement;
|
||||||
|
import javax.lang.model.type.TypeKind;
|
||||||
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
import javax.lang.model.util.Elements;
|
||||||
|
import javax.lang.model.util.Types;
|
||||||
|
import javax.tools.Diagnostic;
|
||||||
|
import javax.tools.Diagnostic.Kind;
|
||||||
|
import javax.tools.FileObject;
|
||||||
|
import javax.tools.StandardLocation;
|
||||||
|
|
||||||
|
@SupportedAnnotationTypes({PLUGIN_ANNOTATION_CLASS, SUBSCRIBE_ANNOTATION_CLASS})
|
||||||
|
public class ApiAnnotationProcessor extends AbstractProcessor {
|
||||||
|
|
||||||
|
private @Nullable String pluginClassFound;
|
||||||
|
private boolean warnedAboutMultiplePlugins;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SourceVersion getSupportedSourceVersion() {
|
||||||
|
return SourceVersion.latestSupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized boolean process(Set<? extends TypeElement> annotations,
|
||||||
|
RoundEnvironment roundEnv) {
|
||||||
|
if (ProcessorUtils.contains(annotations, Subscribe.class)) {
|
||||||
|
for (final Element e : roundEnv.getElementsAnnotatedWith(Subscribe.class)) {
|
||||||
|
if (e.getKind() != ElementKind.METHOD) {
|
||||||
|
this.processingEnv.getMessager().printMessage(
|
||||||
|
Kind.ERROR, "Invalid element of type " + e.getKind()
|
||||||
|
+ " annotated with @Subscribe", e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final ExecutableElement method = (ExecutableElement) e;
|
||||||
|
|
||||||
|
final Messager msg = this.processingEnv.getMessager();
|
||||||
|
if (method.getModifiers().contains(Modifier.STATIC)) {
|
||||||
|
msg.printMessage(Diagnostic.Kind.ERROR, "method must not be static", method);
|
||||||
|
}
|
||||||
|
if (!method.getModifiers().contains(Modifier.PUBLIC)) {
|
||||||
|
msg.printMessage(Diagnostic.Kind.ERROR, "method must be public", method);
|
||||||
|
}
|
||||||
|
if (method.getModifiers().contains(Modifier.ABSTRACT)) {
|
||||||
|
msg.printMessage(Diagnostic.Kind.ERROR,
|
||||||
|
"method must not be abstract", method);
|
||||||
|
}
|
||||||
|
if (method.getEnclosingElement().getKind().isInterface()) {
|
||||||
|
msg.printMessage(Diagnostic.Kind.ERROR,
|
||||||
|
"interfaces cannot declare listeners", method);
|
||||||
|
}
|
||||||
|
if (method.getReturnType().getKind() != TypeKind.VOID
|
||||||
|
&& !this.isTypeSubclass(method.getReturnType(), EVENTTASK_CLASS)) {
|
||||||
|
msg.printMessage(Kind.ERROR, "method must return void or EventTask", method);
|
||||||
|
}
|
||||||
|
final List<? extends VariableElement> parameters = method.getParameters();
|
||||||
|
if (parameters.isEmpty() || !this.isTypeSubclass(parameters.get(0), SUBSCRIBE_ANNOTATION_CLASS)) {
|
||||||
|
msg.printMessage(Diagnostic.Kind.ERROR,
|
||||||
|
"method must have an Event as its first parameter", method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ProcessorUtils.contains(annotations, Plugin.class)) {
|
||||||
|
for (Element element : roundEnv.getElementsAnnotatedWith(Plugin.class)) {
|
||||||
|
if (element.getKind() != ElementKind.CLASS) {
|
||||||
|
processingEnv.getMessager()
|
||||||
|
.printMessage(Diagnostic.Kind.ERROR, "Only classes can be annotated with "
|
||||||
|
+ Plugin.class.getCanonicalName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Name qualifiedName = ((TypeElement) element).getQualifiedName();
|
||||||
|
|
||||||
|
if (Objects.equals(pluginClassFound, qualifiedName.toString())) {
|
||||||
|
if (!warnedAboutMultiplePlugins) {
|
||||||
|
processingEnv.getMessager()
|
||||||
|
.printMessage(Diagnostic.Kind.WARNING, "Velocity does not yet currently support "
|
||||||
|
+ "multiple plugins. We are using " + pluginClassFound
|
||||||
|
+ " for your plugin's main class.");
|
||||||
|
warnedAboutMultiplePlugins = true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Plugin plugin = element.getAnnotation(Plugin.class);
|
||||||
|
if (!SerializedPluginDescription.ID_PATTERN.matcher(plugin.id()).matches()) {
|
||||||
|
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Invalid ID for plugin "
|
||||||
|
+ qualifiedName
|
||||||
|
+ ". IDs must start alphabetically, have alphanumeric characters, and can "
|
||||||
|
+ "contain dashes or underscores.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All good, generate the velocity-plugin.json.
|
||||||
|
SerializedPluginDescription description = SerializedPluginDescription
|
||||||
|
.from(plugin, qualifiedName.toString());
|
||||||
|
try {
|
||||||
|
FileObject object = processingEnv.getFiler()
|
||||||
|
.createResource(StandardLocation.CLASS_OUTPUT, "", "velocity-plugin.json");
|
||||||
|
try (Writer writer = new BufferedWriter(object.openWriter())) {
|
||||||
|
new Gson().toJson(description, writer);
|
||||||
|
}
|
||||||
|
pluginClassFound = qualifiedName.toString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
processingEnv.getMessager()
|
||||||
|
.printMessage(Diagnostic.Kind.ERROR, "Unable to generate plugin file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTypeSubclass(final Element typedElement, final String subclass) {
|
||||||
|
return isTypeSubclass(typedElement.asType(), subclass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTypeSubclass(final TypeMirror typeMirror, final String subclass) {
|
||||||
|
final Elements elements = this.processingEnv.getElementUtils();
|
||||||
|
final Types types = this.processingEnv.getTypeUtils();
|
||||||
|
|
||||||
|
final TypeMirror event = types.getDeclaredType(elements.getTypeElement(subclass));
|
||||||
|
return types.isAssignable(typeMirror, event);
|
||||||
|
}
|
||||||
|
}
|
@ -1,107 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2018 Velocity Contributors
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.velocitypowered.annotationprocessor;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.velocitypowered.api.plugin.Plugin;
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.annotation.processing.AbstractProcessor;
|
|
||||||
import javax.annotation.processing.ProcessingEnvironment;
|
|
||||||
import javax.annotation.processing.RoundEnvironment;
|
|
||||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
|
||||||
import javax.lang.model.SourceVersion;
|
|
||||||
import javax.lang.model.element.Element;
|
|
||||||
import javax.lang.model.element.ElementKind;
|
|
||||||
import javax.lang.model.element.Name;
|
|
||||||
import javax.lang.model.element.TypeElement;
|
|
||||||
import javax.tools.Diagnostic;
|
|
||||||
import javax.tools.FileObject;
|
|
||||||
import javax.tools.StandardLocation;
|
|
||||||
|
|
||||||
@SupportedAnnotationTypes({"com.velocitypowered.api.plugin.Plugin"})
|
|
||||||
public class PluginAnnotationProcessor extends AbstractProcessor {
|
|
||||||
|
|
||||||
private @Nullable String pluginClassFound;
|
|
||||||
private boolean warnedAboutMultiplePlugins;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SourceVersion getSupportedSourceVersion() {
|
|
||||||
return SourceVersion.latestSupported();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized boolean process(Set<? extends TypeElement> annotations,
|
|
||||||
RoundEnvironment roundEnv) {
|
|
||||||
if (roundEnv.processingOver()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Element element : roundEnv.getElementsAnnotatedWith(Plugin.class)) {
|
|
||||||
if (element.getKind() != ElementKind.CLASS) {
|
|
||||||
processingEnv.getMessager()
|
|
||||||
.printMessage(Diagnostic.Kind.ERROR, "Only classes can be annotated with "
|
|
||||||
+ Plugin.class.getCanonicalName());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Name qualifiedName = ((TypeElement) element).getQualifiedName();
|
|
||||||
|
|
||||||
if (Objects.equals(pluginClassFound, qualifiedName.toString())) {
|
|
||||||
if (!warnedAboutMultiplePlugins) {
|
|
||||||
processingEnv.getMessager()
|
|
||||||
.printMessage(Diagnostic.Kind.WARNING, "Velocity does not yet currently support "
|
|
||||||
+ "multiple plugins. We are using " + pluginClassFound
|
|
||||||
+ " for your plugin's main class.");
|
|
||||||
warnedAboutMultiplePlugins = true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Plugin plugin = element.getAnnotation(Plugin.class);
|
|
||||||
if (!SerializedPluginDescription.ID_PATTERN.matcher(plugin.id()).matches()) {
|
|
||||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Invalid ID for plugin "
|
|
||||||
+ qualifiedName
|
|
||||||
+ ". IDs must start alphabetically, have alphanumeric characters, and can "
|
|
||||||
+ "contain dashes or underscores.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All good, generate the velocity-plugin.json.
|
|
||||||
SerializedPluginDescription description = SerializedPluginDescription
|
|
||||||
.from(plugin, qualifiedName.toString());
|
|
||||||
try {
|
|
||||||
FileObject object = processingEnv.getFiler()
|
|
||||||
.createResource(StandardLocation.CLASS_OUTPUT, "", "velocity-plugin.json");
|
|
||||||
try (Writer writer = new BufferedWriter(object.openWriter())) {
|
|
||||||
new Gson().toJson(description, writer);
|
|
||||||
}
|
|
||||||
pluginClassFound = qualifiedName.toString();
|
|
||||||
} catch (IOException e) {
|
|
||||||
processingEnv.getMessager()
|
|
||||||
.printMessage(Diagnostic.Kind.ERROR, "Unable to generate plugin file");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Velocity Contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.velocitypowered.annotationprocessor;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is derived from the Sponge API. The original copyright notice is reproduced below:
|
||||||
|
*
|
||||||
|
* This file is part of SpongeAPI, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) SpongePowered <https://www.spongepowered.org>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
final class ProcessorUtils {
|
||||||
|
|
||||||
|
private ProcessorUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean contains(final Collection<? extends TypeElement> elements, final Class<?> clazz) {
|
||||||
|
if (elements.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String name = clazz.getName();
|
||||||
|
for (final TypeElement element : elements) {
|
||||||
|
if (element.getQualifiedName().contentEquals(name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
com.velocitypowered.annotationprocessor.PluginAnnotationProcessor
|
com.velocitypowered.annotationprocessor.ApiAnnotationProcessor
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren