Allow for class annotations as a default for when an annotation is not present on a method

This commit is contained in:
jmp 2020-10-21 23:51:56 -07:00 committed by Alexander Söderberg
parent d37f2236e7
commit c9d4f39612
7 changed files with 40 additions and 19 deletions

View file

@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Allow for combined presence flags, such that `-a -b -c` is equivalent to `-abc` - Allow for combined presence flags, such that `-a -b -c` is equivalent to `-abc`
- Allow for class annotations as a default for when an annotation is not present on a method.
## [1.0.2] - 2020-10-18 ## [1.0.2] - 2020-10-18

View file

@ -106,6 +106,25 @@ public final class AnnotationParser<C> {
)); ));
} }
protected static <A extends Annotation> @Nullable A getMethodOrClassAnnotation(
final @NonNull Method method,
final @NonNull Class<A> clazz
) {
if (method.isAnnotationPresent(clazz)) {
return method.getAnnotation(clazz);
} else if (method.getDeclaringClass().isAnnotationPresent(clazz)) {
return method.getDeclaringClass().getAnnotation(clazz);
}
return null;
}
protected static <A extends Annotation> boolean methodOrClassHasAnnotation(
final @NonNull Method method,
final @NonNull Class<A> clazz
) {
return getMethodOrClassAnnotation(method, clazz) != null;
}
/** /**
* Register an annotation mapper * Register an annotation mapper
* *
@ -186,8 +205,8 @@ public final class AnnotationParser<C> {
final String commandToken = commandMethod.value().split(" ")[0].split("\\|")[0]; final String commandToken = commandMethod.value().split(" ")[0].split("\\|")[0];
@SuppressWarnings("ALL") final CommandManager manager = this.manager; @SuppressWarnings("ALL") final CommandManager manager = this.manager;
final SimpleCommandMeta.Builder metaBuilder = SimpleCommandMeta.builder() final SimpleCommandMeta.Builder metaBuilder = SimpleCommandMeta.builder()
.with(this.metaFactory.apply(method.getAnnotations())); .with(this.metaFactory.apply(method));
if (method.isAnnotationPresent(Confirmation.class)) { if (methodOrClassHasAnnotation(method, Confirmation.class)) {
metaBuilder.with(CommandConfirmationManager.CONFIRMATION_REQUIRED_META, "true"); metaBuilder.with(CommandConfirmationManager.CONFIRMATION_REQUIRED_META, "true");
} }
@ -245,8 +264,9 @@ public final class AnnotationParser<C> {
} }
} }
if (method.isAnnotationPresent(CommandPermission.class)) { final CommandPermission commandPermission = getMethodOrClassAnnotation(method, CommandPermission.class);
builder = builder.permission(method.getAnnotation(CommandPermission.class).value()); if (commandPermission != null) {
builder = builder.permission(commandPermission.value());
} }
if (commandMethod.requiredSender() != Object.class) { if (commandMethod.requiredSender() != Object.class) {
@ -263,7 +283,7 @@ public final class AnnotationParser<C> {
throw new RuntimeException("Failed to construct command execution handler", e); throw new RuntimeException("Failed to construct command execution handler", e);
} }
/* Check if the command should be hidden */ /* Check if the command should be hidden */
if (method.isAnnotationPresent(Hidden.class)) { if (methodOrClassHasAnnotation(method, Hidden.class)) {
builder = builder.hidden(); builder = builder.hidden();
} }
/* Apply flags */ /* Apply flags */

View file

@ -34,7 +34,7 @@ import java.lang.annotation.Target;
* Maps to {@link StandardParameters#DESCRIPTION} * Maps to {@link StandardParameters#DESCRIPTION}
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target({ElementType.METHOD, ElementType.TYPE})
public @interface CommandDescription { public @interface CommandDescription {
/** /**

View file

@ -31,7 +31,7 @@ import java.lang.annotation.Target;
/** /**
* Equivalent to {@link cloud.commandframework.Command.Builder#permission(String)} * Equivalent to {@link cloud.commandframework.Command.Builder#permission(String)}
*/ */
@Target(ElementType.METHOD) @Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface CommandPermission { public @interface CommandPermission {

View file

@ -32,7 +32,7 @@ import java.lang.annotation.Target;
* Require confirmation for the command * Require confirmation for the command
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target({ElementType.METHOD, ElementType.TYPE})
public @interface Confirmation { public @interface Confirmation {
} }

View file

@ -33,7 +33,7 @@ import java.lang.annotation.Target;
/** /**
* Indicates that the command should be hidden. Similar to {@link Command.Builder#hidden()} * Indicates that the command should be hidden. Similar to {@link Command.Builder#hidden()}
*/ */
@Target(ElementType.METHOD) @Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Hidden { public @interface Hidden {

View file

@ -28,9 +28,10 @@ import cloud.commandframework.meta.CommandMeta;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.function.Function; import java.util.function.Function;
class MetaFactory implements Function<@NonNull Annotation @NonNull [], @NonNull CommandMeta> { class MetaFactory implements Function<@NonNull Method, @NonNull CommandMeta> {
private final AnnotationParser<?> annotationParser; private final AnnotationParser<?> annotationParser;
private final Function<ParserParameters, CommandMeta> metaMapper; private final Function<ParserParameters, CommandMeta> metaMapper;
@ -44,17 +45,16 @@ class MetaFactory implements Function<@NonNull Annotation @NonNull [], @NonNull
} }
@Override @Override
public @NonNull CommandMeta apply(final @NonNull Annotation @NonNull [] annotations) { public @NonNull CommandMeta apply(final @NonNull Method method) {
final ParserParameters parameters = ParserParameters.empty(); final ParserParameters parameters = ParserParameters.empty();
for (final Annotation annotation : annotations) { this.annotationParser.getAnnotationMappers().forEach(((annotationClass, mapper) -> {
@SuppressWarnings("ALL") final Function function = this.annotationParser.getAnnotationMappers() final Annotation annotation = AnnotationParser.getMethodOrClassAnnotation(method, annotationClass);
.get(annotation.annotationType()); if (annotation != null) {
if (function == null) { @SuppressWarnings("ALL") final Function function = (Function) mapper;
continue; //noinspection unchecked
parameters.merge((ParserParameters) function.apply(annotation));
} }
//noinspection unchecked }));
parameters.merge((ParserParameters) function.apply(annotation));
}
return this.metaMapper.apply(parameters); return this.metaMapper.apply(parameters);
} }