diff --git a/annotation-processors/build.gradle.kts b/annotation-processors/build.gradle.kts new file mode 100644 index 000000000..6f13c5321 --- /dev/null +++ b/annotation-processors/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + id("adventure.common-conventions") +} + +dependencies { + annotationProcessor(libs.autoService.processor) + compileOnlyApi(libs.autoService.annotations) + api(libs.jetbrainsAnnotations) +} + +tasks.withType(AbstractPublishToMaven::class) { + isEnabled = false +} diff --git a/annotation-processors/src/main/java/net/kyori/adventure/annotation/processing/PlatformAPIAnnotationProcessor.java b/annotation-processors/src/main/java/net/kyori/adventure/annotation/processing/PlatformAPIAnnotationProcessor.java new file mode 100644 index 000000000..b559feba9 --- /dev/null +++ b/annotation-processors/src/main/java/net/kyori/adventure/annotation/processing/PlatformAPIAnnotationProcessor.java @@ -0,0 +1,66 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * 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. + */ +package net.kyori.adventure.annotation.processing; + +import com.google.auto.service.AutoService; +import java.util.Set; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Processor; +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.TypeElement; +import javax.tools.Diagnostic; +import org.jetbrains.annotations.ApiStatus; + +/** + * Validate that PlatformAPI annotations are used in tandem with the {@link ApiStatus.Internal} annotation. + * + * @since 4.12.0 + */ +@ApiStatus.Internal +@AutoService(Processor.class) +@SupportedAnnotationTypes(PlatformAPIAnnotationProcessor.ADVENTURE_PLATFORMAPI_ANNOTATION) +public class PlatformAPIAnnotationProcessor extends AbstractProcessor { + + public static final String ADVENTURE_PLATFORMAPI_ANNOTATION = "net.kyori.adventure.util.PlatformAPI"; + + @Override + public boolean process(final Set annotations, final RoundEnvironment roundEnv) { + for (final TypeElement annotation : annotations) { + for (final Element element : roundEnv.getElementsAnnotatedWith(annotation)) { + if (element.getAnnotation(ApiStatus.Internal.class) == null) { + this.processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, ADVENTURE_PLATFORMAPI_ANNOTATION + " needs to be used together with " + ApiStatus.Internal.class.getCanonicalName() + ", see PlatformAPI javadocs", element); + } + } + } + return false; + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } +} diff --git a/annotation-processors/src/main/java/net/kyori/adventure/annotation/processing/package-info.java b/annotation-processors/src/main/java/net/kyori/adventure/annotation/processing/package-info.java new file mode 100644 index 000000000..c73b4b1f5 --- /dev/null +++ b/annotation-processors/src/main/java/net/kyori/adventure/annotation/processing/package-info.java @@ -0,0 +1,30 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * 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. + */ +/** + * Annotation processors used by other adventure modules. + */ +@ApiStatus.Internal +package net.kyori.adventure.annotation.processing; + +import org.jetbrains.annotations.ApiStatus; diff --git a/annotation-processors/src/main/resources/META-INF/gradle/incremental.annotation.processors b/annotation-processors/src/main/resources/META-INF/gradle/incremental.annotation.processors new file mode 100644 index 000000000..f292b0fef --- /dev/null +++ b/annotation-processors/src/main/resources/META-INF/gradle/incremental.annotation.processors @@ -0,0 +1 @@ +net.kyori.adventure.annotation.processing.PlatformAPIAnnotationProcessor,isolating diff --git a/api/build.gradle.kts b/api/build.gradle.kts index d6de41fdc..216a14159 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -15,6 +15,7 @@ dependencies { api(libs.examination.string) compileOnlyApi(libs.jetbrainsAnnotations) testImplementation(libs.guava) + annotationProcessor(projects.adventureAnnotationProcessors) } applyJarMetadata("net.kyori.adventure") diff --git a/api/src/main/java/net/kyori/adventure/bossbar/HackyBossBarPlatformBridge.java b/api/src/main/java/net/kyori/adventure/bossbar/HackyBossBarPlatformBridge.java index 564f80498..07c773425 100644 --- a/api/src/main/java/net/kyori/adventure/bossbar/HackyBossBarPlatformBridge.java +++ b/api/src/main/java/net/kyori/adventure/bossbar/HackyBossBarPlatformBridge.java @@ -23,6 +23,7 @@ */ package net.kyori.adventure.bossbar; +import net.kyori.adventure.util.PlatformAPI; import org.jetbrains.annotations.ApiStatus; /** @@ -31,7 +32,8 @@ * * @deprecated not an official API, and may disappear without warning */ -@Deprecated @ApiStatus.Internal +@Deprecated +@PlatformAPI abstract class HackyBossBarPlatformBridge { } diff --git a/api/src/main/java/net/kyori/adventure/util/PlatformAPI.java b/api/src/main/java/net/kyori/adventure/util/PlatformAPI.java new file mode 100644 index 000000000..652315819 --- /dev/null +++ b/api/src/main/java/net/kyori/adventure/util/PlatformAPI.java @@ -0,0 +1,47 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * 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. + */ +package net.kyori.adventure.util; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.jetbrains.annotations.ApiStatus; + +/** + * Elements annotated with the {@link PlatformAPI} annotation are intended for platform implementations of the Adventure API + * only and should not be used by standard developers. They are not public API and may change or be removed without warning at any time. + * + *

This annotation should always be used in tandem with the {@link ApiStatus.Internal} annotation to more consistently produce + * warnings

+ * + * @since 4.12.0 + */ +@ApiStatus.Internal +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PACKAGE, ElementType.ANNOTATION_TYPE}) +public @interface PlatformAPI { +} diff --git a/bom/build.gradle.kts b/bom/build.gradle.kts index 51c6a7f99..ac920132a 100644 --- a/bom/build.gradle.kts +++ b/bom/build.gradle.kts @@ -13,6 +13,7 @@ dependencies { constraints { sequenceOf( "api", + "annotation-processors", "extra-kotlin", "key", "nbt", diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 285fa65be..b360c6f96 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -51,6 +51,8 @@ truth-java8 = { module = "com.google.truth.extensions:truth-java8-extension", ve contractValidator = "ca.stellardrift:contract-validator:1.0.1" errorprone = { module = "com.google.errorprone:error_prone_core", version.ref = "errorprone" } stylecheck = "ca.stellardrift:stylecheck:0.2.0" +autoService-annotations = "com.google.auto.service:auto-service-annotations:1.0.1" +autoService-processor = "com.google.auto.service:auto-service:1.0.1" build-errorpronePlugin = "net.ltgt.gradle:gradle-errorprone-plugin:3.0.1" build-indra = { module = "net.kyori:indra-common", version.ref = "indra" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 24b270f19..a69b587ad 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,6 +28,7 @@ rootProject.name = "adventure-parent" sequenceOf( "api", + "annotation-processors", "bom", "extra-kotlin", "key", diff --git a/text-minimessage/build.gradle.kts b/text-minimessage/build.gradle.kts index c8d66d7a7..62b4e4d97 100644 --- a/text-minimessage/build.gradle.kts +++ b/text-minimessage/build.gradle.kts @@ -8,6 +8,7 @@ description = "A string-based, user-friendly format for representing Minecraft: dependencies { api(projects.adventureApi) testImplementation(project(":adventure-text-serializer-plain")) + annotationProcessor(projects.adventureAnnotationProcessors) } tasks.checkstyleJmh { diff --git a/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessage.java b/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessage.java index ea3b98fac..55262d44c 100644 --- a/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessage.java +++ b/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/MiniMessage.java @@ -30,6 +30,7 @@ import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.minimessage.tree.Node; import net.kyori.adventure.text.serializer.ComponentSerializer; +import net.kyori.adventure.util.PlatformAPI; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -299,6 +300,7 @@ interface Builder extends AbstractBuilder { * @hidden */ @ApiStatus.Internal + @PlatformAPI interface Provider { /** * Provides a standard {@link MiniMessage} instance. @@ -307,6 +309,7 @@ interface Provider { * @since 4.10.0 */ @ApiStatus.Internal + @PlatformAPI @NotNull MiniMessage miniMessage(); /** @@ -316,6 +319,7 @@ interface Provider { * @since 4.10.0 */ @ApiStatus.Internal + @PlatformAPI @NotNull Consumer builder(); } } diff --git a/text-serializer-gson/build.gradle.kts b/text-serializer-gson/build.gradle.kts index e15553751..04e83fd62 100644 --- a/text-serializer-gson/build.gradle.kts +++ b/text-serializer-gson/build.gradle.kts @@ -7,6 +7,7 @@ dependencies { api(projects.adventureApi) api(libs.gson) testImplementation(projects.adventureNbt) + annotationProcessor(projects.adventureAnnotationProcessors) } applyJarMetadata("net.kyori.adventure.text.serializer.gson") diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializer.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializer.java index d84be117b..838e2d8d0 100644 --- a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializer.java +++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializer.java @@ -32,6 +32,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.ComponentSerializer; import net.kyori.adventure.util.Buildable; +import net.kyori.adventure.util.PlatformAPI; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -163,6 +164,7 @@ interface Builder extends AbstractBuilder, Buildable.Bu * @since 4.8.0 */ @ApiStatus.Internal + @PlatformAPI interface Provider { /** * Provides a standard {@link GsonComponentSerializer}. @@ -171,6 +173,7 @@ interface Provider { * @since 4.8.0 */ @ApiStatus.Internal + @PlatformAPI @NotNull GsonComponentSerializer gson(); /** @@ -180,6 +183,7 @@ interface Provider { * @since 4.8.0 */ @ApiStatus.Internal + @PlatformAPI @NotNull GsonComponentSerializer gsonLegacy(); /** @@ -189,6 +193,7 @@ interface Provider { * @since 4.8.0 */ @ApiStatus.Internal + @PlatformAPI @NotNull Consumer builder(); } } diff --git a/text-serializer-legacy/build.gradle.kts b/text-serializer-legacy/build.gradle.kts index 9a12a5ccd..cd498b73d 100644 --- a/text-serializer-legacy/build.gradle.kts +++ b/text-serializer-legacy/build.gradle.kts @@ -4,6 +4,7 @@ plugins { dependencies { api(projects.adventureApi) + annotationProcessor(projects.adventureAnnotationProcessors) } applyJarMetadata("net.kyori.adventure.text.serializer.legacy") diff --git a/text-serializer-legacy/src/main/java/net/kyori/adventure/text/serializer/legacy/LegacyComponentSerializer.java b/text-serializer-legacy/src/main/java/net/kyori/adventure/text/serializer/legacy/LegacyComponentSerializer.java index 8765ae5a9..4f2294c23 100644 --- a/text-serializer-legacy/src/main/java/net/kyori/adventure/text/serializer/legacy/LegacyComponentSerializer.java +++ b/text-serializer-legacy/src/main/java/net/kyori/adventure/text/serializer/legacy/LegacyComponentSerializer.java @@ -34,6 +34,7 @@ import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.serializer.ComponentSerializer; import net.kyori.adventure.util.Buildable; +import net.kyori.adventure.util.PlatformAPI; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -272,6 +273,7 @@ interface Builder extends AbstractBuilder, Buildable. * @since 4.8.0 */ @ApiStatus.Internal + @PlatformAPI interface Provider { /** * Provides a {@link LegacyComponentSerializer} using {@link #AMPERSAND_CHAR}. @@ -280,6 +282,7 @@ interface Provider { * @since 4.8.0 */ @ApiStatus.Internal + @PlatformAPI @NotNull LegacyComponentSerializer legacyAmpersand(); /** @@ -289,6 +292,7 @@ interface Provider { * @since 4.8.0 */ @ApiStatus.Internal + @PlatformAPI @NotNull LegacyComponentSerializer legacySection(); /** @@ -298,6 +302,7 @@ interface Provider { * @since 4.8.0 */ @ApiStatus.Internal + @PlatformAPI @NotNull Consumer legacy(); } } diff --git a/text-serializer-plain/build.gradle.kts b/text-serializer-plain/build.gradle.kts index 9c3b9ae2f..02bc22929 100644 --- a/text-serializer-plain/build.gradle.kts +++ b/text-serializer-plain/build.gradle.kts @@ -4,6 +4,7 @@ plugins { dependencies { api(projects.adventureApi) + annotationProcessor(projects.adventureAnnotationProcessors) } applyJarMetadata("net.kyori.adventure.text.serializer.plain") diff --git a/text-serializer-plain/src/main/java/net/kyori/adventure/text/serializer/plain/PlainTextComponentSerializer.java b/text-serializer-plain/src/main/java/net/kyori/adventure/text/serializer/plain/PlainTextComponentSerializer.java index 323e1ee9c..87b027a18 100644 --- a/text-serializer-plain/src/main/java/net/kyori/adventure/text/serializer/plain/PlainTextComponentSerializer.java +++ b/text-serializer-plain/src/main/java/net/kyori/adventure/text/serializer/plain/PlainTextComponentSerializer.java @@ -32,6 +32,7 @@ import net.kyori.adventure.text.flattener.ComponentFlattener; import net.kyori.adventure.text.serializer.ComponentSerializer; import net.kyori.adventure.util.Buildable; +import net.kyori.adventure.util.PlatformAPI; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -109,6 +110,7 @@ interface Builder extends AbstractBuilder, Buildab * @since 4.8.0 */ @ApiStatus.Internal + @PlatformAPI interface Provider { /** * Provides a {@link PlainTextComponentSerializer}. @@ -117,6 +119,7 @@ interface Provider { * @since 4.8.0 */ @ApiStatus.Internal + @PlatformAPI @NotNull PlainTextComponentSerializer plainTextSimple(); /** @@ -126,6 +129,7 @@ interface Provider { * @since 4.8.0 */ @ApiStatus.Internal + @PlatformAPI @NotNull Consumer plainText(); } }