Skip to content

Commit 85e5235

Browse files
authored
Support suspending parsers. (#715)
* Support suspending parsers. * Update KotlinAnnotatedMethods.kt * Update KotlinAnnotatedMethods.kt * Fix #713 * remove Nonnul to make the kotlin happy. * Revert "Fix #713" This reverts commit 1260d94.
1 parent 550317b commit 85e5235

File tree

6 files changed

+401
-76
lines changed

6 files changed

+401
-76
lines changed

cloud-annotations/src/main/java/org/incendo/cloud/annotations/AnnotationParser.java

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
import org.incendo.cloud.annotations.extractor.FlagExtractorImpl;
7171
import org.incendo.cloud.annotations.extractor.StandardArgumentExtractor;
7272
import org.incendo.cloud.annotations.injection.RawArgs;
73-
import org.incendo.cloud.annotations.parser.MethodArgumentParser;
73+
import org.incendo.cloud.annotations.parser.MethodArgumentParserFactory;
7474
import org.incendo.cloud.annotations.parser.Parser;
7575
import org.incendo.cloud.annotations.processing.CommandContainer;
7676
import org.incendo.cloud.annotations.processing.CommandContainerProcessor;
@@ -85,7 +85,7 @@
8585
import org.incendo.cloud.internal.CommandInputTokenizer;
8686
import org.incendo.cloud.meta.CommandMeta;
8787
import org.incendo.cloud.meta.CommandMetaBuilder;
88-
import org.incendo.cloud.parser.ArgumentParser;
88+
import org.incendo.cloud.parser.ParserDescriptor;
8989
import org.incendo.cloud.parser.ParserParameter;
9090
import org.incendo.cloud.parser.ParserParameters;
9191
import org.incendo.cloud.parser.flag.CommandFlag;
@@ -133,6 +133,7 @@ public final class AnnotationParser<C> {
133133
private FlagAssembler flagAssembler;
134134
private CommandExtractor commandExtractor;
135135
private SuggestionProviderFactory<C> suggestionProviderFactory;
136+
private MethodArgumentParserFactory<C> methodArgumentParserFactory;
136137
private ExceptionHandlerFactory<C> exceptionHandlerFactory;
137138
private DescriptionMapper descriptionMapper;
138139
private DefaultValueRegistry<C> defaultValueRegistry;
@@ -212,6 +213,7 @@ public AnnotationParser(
212213
this.argumentAssembler = new ArgumentAssemblerImpl<>(this);
213214
this.commandExtractor = new CommandExtractorImpl(this);
214215
this.suggestionProviderFactory = SuggestionProviderFactory.defaultFactory();
216+
this.methodArgumentParserFactory = MethodArgumentParserFactory.defaultFactory();
215217
this.exceptionHandlerFactory = ExceptionHandlerFactory.defaultFactory();
216218
this.builderDecorators = new ArrayList<>();
217219
this.defaultValueRegistry = new DefaultValueRegistryImpl<>();
@@ -570,6 +572,26 @@ public void suggestionProviderFactory(final @NonNull SuggestionProviderFactory<C
570572
this.suggestionProviderFactory = suggestionProviderFactory;
571573
}
572574

575+
/**
576+
* Returns the method argument parser factory.
577+
*
578+
* @return the method argument parser factory
579+
*/
580+
@API(status = API.Status.EXPERIMENTAL)
581+
public @NonNull MethodArgumentParserFactory<C> methodArgumentParserFactory() {
582+
return this.methodArgumentParserFactory;
583+
}
584+
585+
/**
586+
* Sets the method argument parser factory.
587+
*
588+
* @param methodArgumentParserFactory new method argument parser factory
589+
*/
590+
@API(status = API.Status.EXPERIMENTAL)
591+
public void methodArgumentParserFactory(final @NonNull MethodArgumentParserFactory<C> methodArgumentParserFactory) {
592+
this.methodArgumentParserFactory = methodArgumentParserFactory;
593+
}
594+
573595
/**
574596
* Returns the exception provider factory.
575597
*
@@ -859,25 +881,17 @@ private <T> void parseParsers(final @NonNull T instance) {
859881
)
860882
));
861883
}
862-
final MethodArgumentParser<C, ?> methodArgumentParser = new MethodArgumentParser<>(
884+
final ParserDescriptor<C, ?> parserDescriptor = this.methodArgumentParserFactory.createArgumentParser(
863885
suggestionProvider,
864886
instance,
865887
method,
866888
this.manager.parameterInjectorRegistry()
867889
);
868-
final Function<ParserParameters, ArgumentParser<C, ?>> parserFunction =
869-
parameters -> methodArgumentParser;
870890
final String name = this.processString(parser.name());
871891
if (name.isEmpty()) {
872-
this.manager.parserRegistry().registerParserSupplier(
873-
TypeToken.get(method.getGenericReturnType()),
874-
parserFunction
875-
);
892+
this.manager.parserRegistry().registerParser(parserDescriptor);
876893
} else {
877-
this.manager.parserRegistry().registerNamedParserSupplier(
878-
name,
879-
parserFunction
880-
);
894+
this.manager.parserRegistry().registerNamedParser(name, parserDescriptor);
881895
}
882896
} catch (final Exception e) {
883897
throw new RuntimeException(e);
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//
2+
// MIT License
3+
//
4+
// Copyright (c) 2024 Incendo
5+
//
6+
// Permission is hereby granted, free of charge, to any person obtaining a copy
7+
// of this software and associated documentation files (the "Software"), to deal
8+
// in the Software without restriction, including without limitation the rights
9+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
// copies of the Software, and to permit persons to whom the Software is
11+
// furnished to do so, subject to the following conditions:
12+
//
13+
// The above copyright notice and this permission notice shall be included in all
14+
// copies or substantial portions of the Software.
15+
//
16+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
// SOFTWARE.
23+
//
24+
package org.incendo.cloud.annotations.parser;
25+
26+
import java.lang.reflect.Method;
27+
import org.apiguardian.api.API;
28+
import org.checkerframework.checker.nullness.qual.NonNull;
29+
import org.incendo.cloud.injection.ParameterInjectorRegistry;
30+
import org.incendo.cloud.parser.ParserDescriptor;
31+
import org.incendo.cloud.suggestion.SuggestionProvider;
32+
33+
@FunctionalInterface
34+
@API(status = API.Status.EXPERIMENTAL)
35+
public interface MethodArgumentParserFactory<C> {
36+
37+
/**
38+
* Returns a factory that produces {@link MethodArgumentParserFactoryImpl} instances.
39+
*
40+
* @param <C> the command sender type
41+
* @return the created factory
42+
*/
43+
static <C> @NonNull MethodArgumentParserFactory<C> defaultFactory() {
44+
return new MethodArgumentParserFactoryImpl<>();
45+
}
46+
47+
/**
48+
* Creates a suggestion provider using the given {@code method}.
49+
*
50+
* @param suggestionProvider suggestion provider
51+
* @param instance parsed instance
52+
* @param method suggestion method
53+
* @param injectorRegistry injector registry
54+
* @return the suggestion provider
55+
*/
56+
@NonNull ParserDescriptor<C, ?> createArgumentParser(
57+
@NonNull SuggestionProvider<C> suggestionProvider,
58+
@NonNull Object instance,
59+
@NonNull Method method,
60+
@NonNull ParameterInjectorRegistry<C> injectorRegistry
61+
);
62+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//
2+
// MIT License
3+
//
4+
// Copyright (c) 2024 Incendo
5+
//
6+
// Permission is hereby granted, free of charge, to any person obtaining a copy
7+
// of this software and associated documentation files (the "Software"), to deal
8+
// in the Software without restriction, including without limitation the rights
9+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
// copies of the Software, and to permit persons to whom the Software is
11+
// furnished to do so, subject to the following conditions:
12+
//
13+
// The above copyright notice and this permission notice shall be included in all
14+
// copies or substantial portions of the Software.
15+
//
16+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
// SOFTWARE.
23+
//
24+
package org.incendo.cloud.annotations.parser;
25+
26+
import io.leangen.geantyref.TypeToken;
27+
import java.lang.reflect.Method;
28+
import org.checkerframework.checker.nullness.qual.NonNull;
29+
import org.incendo.cloud.injection.ParameterInjectorRegistry;
30+
import org.incendo.cloud.parser.ParserDescriptor;
31+
import org.incendo.cloud.suggestion.SuggestionProvider;
32+
33+
/**
34+
* Represents a method argument parser annotated with {@link Parser}
35+
*
36+
* @param <C> command sender type
37+
*/
38+
public final class MethodArgumentParserFactoryImpl<C> implements MethodArgumentParserFactory<C> {
39+
40+
@Override
41+
public @NonNull ParserDescriptor<C, ?> createArgumentParser(
42+
final @NonNull SuggestionProvider<C> suggestionProvider,
43+
final @NonNull Object instance,
44+
final @NonNull Method method,
45+
final @NonNull ParameterInjectorRegistry<C> injectorRegistry
46+
) {
47+
return ParserDescriptor.of(
48+
new MethodArgumentParser<>(suggestionProvider, instance, method, injectorRegistry),
49+
TypeToken.get(method.getGenericReturnType())
50+
);
51+
}
52+
}

cloud-core/src/main/java/org/incendo/cloud/parser/ArgumentParser.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public interface ArgumentParser<C, T> extends SuggestionProviderHolder<C> {
102102
*/
103103
@API(status = API.Status.STABLE)
104104
default @NonNull CompletableFuture<@NonNull ArgumentParseResult<T>> parseFuture(
105-
@NonNull CommandContext<@NonNull C> commandContext,
105+
@NonNull CommandContext<C> commandContext,
106106
@NonNull CommandInput commandInput
107107
) {
108108
return CompletableFuture.completedFuture(this.parse(commandContext, commandInput));
@@ -215,7 +215,7 @@ interface FutureArgumentParser<C, T> extends ArgumentParser<C, T> {
215215

216216
@Override
217217
@NonNull CompletableFuture<@NonNull ArgumentParseResult<T>> parseFuture(
218-
@NonNull CommandContext<@NonNull C> commandContext,
218+
@NonNull CommandContext<C> commandContext,
219219
@NonNull CommandInput commandInput
220220
);
221221
}

0 commit comments

Comments
 (0)