Skip to content

Commit 6282592

Browse files
committed
Can now parse basic parameter types
1 parent 3261c1b commit 6282592

File tree

13 files changed

+198
-44
lines changed

13 files changed

+198
-44
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package fr.zcraft.quartzlib.components.commands;
2+
3+
@FunctionalInterface
4+
public interface ArgumentType<T> {
5+
T parse(String raw);
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package fr.zcraft.quartzlib.components.commands;
2+
3+
import fr.zcraft.quartzlib.components.commands.ArgumentType;
4+
5+
public class ArgumentTypeHandler<T> {
6+
private final Class<T> resultType;
7+
private final ArgumentType<T> typeHandler;
8+
9+
public ArgumentTypeHandler(Class<T> resultType, ArgumentType<T> typeHandler) {
10+
this.resultType = resultType;
11+
this.typeHandler = typeHandler;
12+
}
13+
14+
public ArgumentType<T> getTypeHandler() {
15+
return typeHandler;
16+
}
17+
18+
public Class<T> getResultType() {
19+
return resultType;
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package fr.zcraft.quartzlib.components.commands;
2+
3+
import fr.zcraft.quartzlib.components.commands.arguments.primitive.IntegerTypeHandler;
4+
5+
import java.util.HashMap;
6+
import java.util.Map;
7+
import java.util.Optional;
8+
9+
class ArgumentTypeHandlerCollection {
10+
private final Map<Class<?>, ArgumentTypeHandler<?>> argumentTypeHandlerMap = new HashMap<>();
11+
12+
public ArgumentTypeHandlerCollection () {
13+
this.registerNativeTypes();
14+
}
15+
16+
public <T> void register(ArgumentTypeHandler<T> typeHandler)
17+
{
18+
argumentTypeHandlerMap.put(typeHandler.getResultType(), typeHandler);
19+
}
20+
21+
public Optional<ArgumentTypeHandler<?>> findTypeHandler(Class<?> resultType) {
22+
return Optional.ofNullable(argumentTypeHandlerMap.get(resultType));
23+
}
24+
25+
private void registerNativeTypes () {
26+
register(new ArgumentTypeHandler<>(Integer.class, new IntegerTypeHandler()));
27+
28+
register(new ArgumentTypeHandler<>(String.class, s -> s));
29+
}
30+
}

src/main/java/fr/zcraft/quartzlib/components/commands/internal/CommandEndpoint.java renamed to src/main/java/fr/zcraft/quartzlib/components/commands/CommandEndpoint.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
package fr.zcraft.quartzlib.components.commands.internal;
2-
3-
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
1+
package fr.zcraft.quartzlib.components.commands;
42

53
import java.util.ArrayList;
64
import java.util.List;

src/main/java/fr/zcraft/quartzlib/components/commands/internal/CommandGroup.java renamed to src/main/java/fr/zcraft/quartzlib/components/commands/CommandGroup.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package fr.zcraft.quartzlib.components.commands.internal;
1+
package fr.zcraft.quartzlib.components.commands;
22

33
import java.util.Arrays;
44
import java.util.HashMap;
@@ -11,15 +11,15 @@ class CommandGroup extends CommandNode {
1111

1212
private final Map<String, CommandNode> subCommands = new HashMap<>();
1313

14-
public CommandGroup(Class<?> commandGroupClass, Supplier<?> classInstanceSupplier, String name) {
15-
this(commandGroupClass, classInstanceSupplier, name, null);
14+
public CommandGroup(Class<?> commandGroupClass, Supplier<?> classInstanceSupplier, String name, ArgumentTypeHandlerCollection typeHandlerCollection) {
15+
this(commandGroupClass, classInstanceSupplier, name, typeHandlerCollection, null);
1616
}
1717

18-
public CommandGroup(Class<?> commandGroupClass, Supplier<?> classInstanceSupplier, String name, CommandGroup parent) {
18+
public CommandGroup(Class<?> commandGroupClass, Supplier<?> classInstanceSupplier, String name, ArgumentTypeHandlerCollection typeHandlerCollection, CommandGroup parent) {
1919
super(name, parent);
2020
this.commandGroupClass = commandGroupClass;
2121
this.classInstanceSupplier = classInstanceSupplier;
22-
DiscoveryUtils.getCommandMethods(commandGroupClass).forEach(this::addMethod);
22+
DiscoveryUtils.getCommandMethods(commandGroupClass, typeHandlerCollection).forEach(this::addMethod);
2323
}
2424

2525
public Iterable<CommandNode> getSubCommands () {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package fr.zcraft.quartzlib.components.commands;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
import java.util.function.Supplier;
6+
7+
public class CommandManager {
8+
private final Map<String, CommandNode> rootCommands = new HashMap<>();
9+
private final ArgumentTypeHandlerCollection typeHandlerCollection = new ArgumentTypeHandlerCollection();
10+
11+
public <T> void registerCommand(String name, Class<T> commandType, Supplier<T> commandClassSupplier) {
12+
CommandGroup group = new CommandGroup(commandType, commandClassSupplier, name, typeHandlerCollection);
13+
rootCommands.put(name, group);
14+
}
15+
16+
public void run(String commandName, String... args) {
17+
((CommandGroup) rootCommands.get(commandName)).run(args); // TODO
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package fr.zcraft.quartzlib.components.commands;
2+
3+
import java.lang.reflect.InvocationTargetException;
4+
import java.lang.reflect.Method;
5+
import java.util.Arrays;
6+
7+
class CommandMethod {
8+
private final Method method;
9+
private final String name;
10+
private final CommandMethodArgument[] arguments;
11+
12+
CommandMethod(Method method, ArgumentTypeHandlerCollection typeHandlerCollection) {
13+
this.method = method;
14+
this.name = method.getName();
15+
16+
arguments = Arrays.stream(method.getParameters())
17+
.map(p -> new CommandMethodArgument(p, typeHandlerCollection))
18+
.toArray(CommandMethodArgument[]::new);
19+
}
20+
21+
public String getName() {
22+
return name;
23+
}
24+
25+
public void run(Object target, String[] args) {
26+
Object[] parsedArgs = parseArguments(args);
27+
try {
28+
this.method.invoke(target, parsedArgs);
29+
} catch (IllegalAccessException | InvocationTargetException e) {
30+
e.printStackTrace(); // TODO
31+
}
32+
}
33+
34+
private Object[] parseArguments(String[] args) {
35+
Object[] parsed = new Object[args.length];
36+
37+
for (int i = 0; i < args.length; i++) {
38+
parsed[i] = arguments[i].parse(args[i]);
39+
}
40+
41+
return parsed;
42+
}
43+
44+
public CommandMethodArgument[] getArguments() {
45+
return arguments;
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package fr.zcraft.quartzlib.components.commands;
2+
3+
import java.lang.reflect.Parameter;
4+
5+
public class CommandMethodArgument {
6+
private final Parameter parameter;
7+
private final ArgumentTypeHandler<?> typeHandler;
8+
9+
public CommandMethodArgument(Parameter parameter, ArgumentTypeHandlerCollection typeHandlerCollection) {
10+
this.parameter = parameter;
11+
this.typeHandler = typeHandlerCollection.findTypeHandler(parameter.getType()).get(); // FIXME: handle unknown types
12+
}
13+
14+
public Object parse(String raw) {
15+
return this.typeHandler.getTypeHandler().parse(raw);
16+
}
17+
}

src/main/java/fr/zcraft/quartzlib/components/commands/internal/CommandNode.java renamed to src/main/java/fr/zcraft/quartzlib/components/commands/CommandNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package fr.zcraft.quartzlib.components.commands.internal;
1+
package fr.zcraft.quartzlib.components.commands;
22

33
abstract class CommandNode {
44
private final String name;

src/main/java/fr/zcraft/quartzlib/components/commands/internal/DiscoveryUtils.java renamed to src/main/java/fr/zcraft/quartzlib/components/commands/DiscoveryUtils.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1-
package fr.zcraft.quartzlib.components.commands.internal;
1+
package fr.zcraft.quartzlib.components.commands;
22

33
import java.lang.reflect.Constructor;
44
import java.lang.reflect.InvocationTargetException;
5+
import java.lang.reflect.Method;
56
import java.lang.reflect.Modifier;
67
import java.util.Arrays;
78
import java.util.function.Supplier;
89
import java.util.stream.Stream;
910

1011
abstract class DiscoveryUtils {
11-
public static Stream<CommandMethod> getCommandMethods(Class<?> commandGroupClass) {
12+
public static Stream<CommandMethod> getCommandMethods(Class<?> commandGroupClass, ArgumentTypeHandlerCollection typeHandlerCollection) {
1213
return Arrays.stream(commandGroupClass.getDeclaredMethods())
1314
.filter(m -> Modifier.isPublic(m.getModifiers()) && !Modifier.isStatic(m.getModifiers()))
14-
.map(CommandMethod::new);
15+
.map((Method method) -> new CommandMethod(method, typeHandlerCollection));
1516
}
1617

1718
public static Supplier<?> getClassConstructorSupplier (Class<?> commandGroupClass) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package fr.zcraft.quartzlib.components.commands.arguments.primitive;
2+
3+
import fr.zcraft.quartzlib.components.commands.ArgumentType;
4+
5+
public class IntegerTypeHandler implements ArgumentType<Integer> {
6+
@Override
7+
public Integer parse(String raw) {
8+
return Integer.parseInt(raw, 10); // TODO: handle exceptions
9+
}
10+
}

src/main/java/fr/zcraft/quartzlib/components/commands/internal/CommandMethod.java

-26
This file was deleted.

src/test/java/fr/zcraft/quartzlib/components/commands/internal/CommandGraphTests.java renamed to src/test/java/fr/zcraft/quartzlib/components/commands/CommandGraphTests.java

+37-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
package fr.zcraft.quartzlib.components.commands.internal;
1+
package fr.zcraft.quartzlib.components.commands;
22

33
import org.junit.jupiter.api.Assertions;
4+
import org.junit.jupiter.api.BeforeEach;
45
import org.junit.jupiter.api.Test;
56

67
import java.util.stream.StreamSupport;
@@ -16,20 +17,27 @@ static public void staticMethod () {}
1617
}
1718

1819
public class CommandGraphTests {
20+
private CommandManager commands;
21+
22+
@BeforeEach
23+
public void beforeEach () {
24+
commands = new CommandManager();
25+
}
26+
1927
@Test public void canDiscoverBasicSubcommands() {
2028
class FooCommand {
2129
public void add () {}
2230
public void get () {}
2331
public void list () {}
2432
}
2533

26-
CommandGroup commandGroup = new CommandGroup(FooCommand.class, () -> new FooCommand(), "foo");
34+
CommandGroup commandGroup = new CommandGroup(FooCommand.class, () -> new FooCommand(), "foo", new ArgumentTypeHandlerCollection());
2735
String[] commandNames = StreamSupport.stream(commandGroup.getSubCommands().spliterator(), false).map(CommandNode::getName).toArray(String[]::new);
2836
Assertions.assertArrayEquals(new String[] {"add", "get", "list"}, commandNames);
2937
}
3038

3139
@Test public void onlyDiscoversPublicMethods() {
32-
CommandGroup commandGroup = new CommandGroup(CommandWithStatics.class, () -> new CommandWithStatics(), "foo");
40+
CommandGroup commandGroup = new CommandGroup(CommandWithStatics.class, () -> new CommandWithStatics(), "foo", new ArgumentTypeHandlerCollection());
3341
String[] commandNames = StreamSupport.stream(commandGroup.getSubCommands().spliterator(), false).map(CommandNode::getName).toArray(String[]::new);
3442
Assertions.assertArrayEquals(new String[] {"add", "delete"}, commandNames);
3543
}
@@ -43,9 +51,32 @@ class FooCommand {
4351
public void list () { ran[2] = true; }
4452
}
4553

46-
FooCommand f = new FooCommand();
47-
CommandGroup commandGroup = new CommandGroup(FooCommand.class, () -> new FooCommand(),"foo");
48-
commandGroup.run("get");
54+
commands.registerCommand("foo", FooCommand.class, () -> new FooCommand());
55+
commands.run("foo", "get");
4956
Assertions.assertArrayEquals(new boolean[] { false, true, false }, ran);
5057
}
58+
59+
@Test public void canReceiveStringArguments() {
60+
final String[] argValue = {""};
61+
62+
class FooCommand {
63+
public void add (String arg) { argValue[0] = arg; }
64+
}
65+
66+
commands.registerCommand("foo", FooCommand.class, () -> new FooCommand());
67+
commands.run("foo", "add", "pomf");
68+
Assertions.assertArrayEquals(new String[] { "pomf" }, argValue);
69+
}
70+
71+
@Test public void canReceiveParsedArguments() {
72+
final int[] argValue = {0};
73+
74+
class FooCommand {
75+
public void add (Integer arg) { argValue[0] = arg; }
76+
}
77+
78+
commands.registerCommand("foo", FooCommand.class, () -> new FooCommand());
79+
commands.run("foo", "add", "42");
80+
Assertions.assertArrayEquals(new int[] { 42 }, argValue);
81+
}
5182
}

0 commit comments

Comments
 (0)