diff --git a/src/main/java/io/airlift/airline/Accessor.java b/src/main/java/io/airlift/airline/Accessor.java index 9122be6bf..31cde8e32 100644 --- a/src/main/java/io/airlift/airline/Accessor.java +++ b/src/main/java/io/airlift/airline/Accessor.java @@ -5,6 +5,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import io.airlift.airline.factory.DefaultConstructorFactory; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; @@ -77,7 +78,7 @@ public Object getValue(Object instance) try { Object nextInstance = intermediateField.get(instance); if (nextInstance == null) { - nextInstance = ParserUtil.createInstance(intermediateField.getType()); + nextInstance = new DefaultConstructorFactory().createInstance(intermediateField.getType()); intermediateField.set(instance, nextInstance); } instance = nextInstance; diff --git a/src/main/java/io/airlift/airline/Cli.java b/src/main/java/io/airlift/airline/Cli.java index 13f7533f1..4365fa011 100644 --- a/src/main/java/io/airlift/airline/Cli.java +++ b/src/main/java/io/airlift/airline/Cli.java @@ -23,23 +23,22 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; -import io.airlift.airline.model.ArgumentsMetadata; -import io.airlift.airline.model.CommandGroupMetadata; -import io.airlift.airline.model.CommandMetadata; -import io.airlift.airline.model.GlobalMetadata; -import io.airlift.airline.model.MetadataLoader; -import io.airlift.airline.model.OptionMetadata; +import io.airlift.airline.factory.CommandFactory; +import io.airlift.airline.factory.DefaultConstructorFactory; +import io.airlift.airline.model.*; import java.util.List; import java.util.Map; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Maps.newHashMap; -import static io.airlift.airline.ParserUtil.createInstance; +import static io.airlift.airline.ParserUtil.configureInstance; public class Cli { - public static CliBuilder builder(String name) + private final CommandFactory commandFactory; + + public static CliBuilder builder(String name) { Preconditions.checkNotNull(name, "name is null"); return new CliBuilder(name); @@ -64,9 +63,11 @@ private Cli(String name, TypeConverter typeConverter, Class defaultCommand, Iterable> defaultGroupCommands, - Iterable> groups) + Iterable> groups, + CommandFactory commandFactory) { - Preconditions.checkNotNull(name, "name is null"); + this.commandFactory = commandFactory; + Preconditions.checkNotNull(name, "name is null"); Preconditions.checkNotNull(typeConverter, "typeConverter is null"); CommandMetadata defaultCommandMetadata = null; @@ -117,13 +118,14 @@ public C parse(Iterable args) CommandMetadata command = state.getCommand(); - return createInstance(command.getType(), - command.getAllOptions(), - state.getParsedOptions(), - command.getArguments(), - state.getParsedArguments(), - command.getMetadataInjections(), - ImmutableMap., Object>of(GlobalMetadata.class, metadata)); + C instance = (C) commandFactory.createInstance(command.getType()); + return configureInstance(instance, + command.getAllOptions(), + state.getParsedOptions(), + command.getArguments(), + state.getParsedArguments(), + command.getMetadataInjections(), + ImmutableMap., Object>of(GlobalMetadata.class, metadata)); } private void validate(ParseState state) @@ -168,6 +170,7 @@ public static class CliBuilder protected final String name; protected String description; protected TypeConverter typeConverter = new TypeConverter(); + protected CommandFactory commandFactory = new DefaultConstructorFactory(); protected String optionSeparators; private Class defaultCommand; private final List> defaultCommandGroupCommands = newArrayList(); @@ -202,11 +205,18 @@ public CliBuilder withDescription(String description) // return this; // } - public CliBuilder withDefaultCommand(Class defaultCommand) - { - this.defaultCommand = defaultCommand; - return this; - } + + public CliBuilder withCommandFactory(CommandFactory commandFactory) + { + this.commandFactory = commandFactory; + return this; + } + + public CliBuilder withDefaultCommand(Class defaultCommand) + { + this.defaultCommand = defaultCommand; + return this; + } public CliBuilder withCommand(Class command) { @@ -243,7 +253,7 @@ public GroupBuilder withGroup(String name) public Cli build() { - return new Cli(name, description, typeConverter, defaultCommand, defaultCommandGroupCommands, groups.values()); + return new Cli(name, description, typeConverter, defaultCommand, defaultCommandGroupCommands, groups.values(), commandFactory); } } diff --git a/src/main/java/io/airlift/airline/ParserUtil.java b/src/main/java/io/airlift/airline/ParserUtil.java index 72d568b38..6f11c31f1 100644 --- a/src/main/java/io/airlift/airline/ParserUtil.java +++ b/src/main/java/io/airlift/airline/ParserUtil.java @@ -12,30 +12,14 @@ public class ParserUtil { - public static T createInstance(Class type) + public static T configureInstance(T commandInstance, + Iterable options, + ListMultimap parsedOptions, + ArgumentsMetadata arguments, + Iterable parsedArguments, + Iterable metadataInjection, + Map, Object> bindings) { - if (type != null) { - try { - return type.getConstructor().newInstance(); - } - catch (Exception e) { - throw new ParseException(e, "Unable to create instance %s", type.getName()); - } - } - return null; - } - - public static T createInstance(Class type, - Iterable options, - ListMultimap parsedOptions, - ArgumentsMetadata arguments, - Iterable parsedArguments, - Iterable metadataInjection, - Map, Object> bindings) - { - // create the command instance - T commandInstance = (T) ParserUtil.createInstance(type); - // inject options for (OptionMetadata option : options) { List values = parsedOptions.get(option); diff --git a/src/main/java/io/airlift/airline/SingleCommand.java b/src/main/java/io/airlift/airline/SingleCommand.java index 8dc5d116d..a4f445a2f 100644 --- a/src/main/java/io/airlift/airline/SingleCommand.java +++ b/src/main/java/io/airlift/airline/SingleCommand.java @@ -20,6 +20,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import io.airlift.airline.factory.CommandFactory; +import io.airlift.airline.factory.DefaultConstructorFactory; import io.airlift.airline.model.ArgumentsMetadata; import io.airlift.airline.model.CommandMetadata; import io.airlift.airline.model.MetadataLoader; @@ -28,7 +30,7 @@ import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; -import static io.airlift.airline.ParserUtil.createInstance; +import static io.airlift.airline.ParserUtil.configureInstance; public class SingleCommand { @@ -66,13 +68,15 @@ public C parse(Iterable args) CommandMetadata command = state.getCommand(); - return createInstance(command.getType(), - command.getAllOptions(), - state.getParsedOptions(), - command.getArguments(), - state.getParsedArguments(), - command.getMetadataInjections(), - ImmutableMap., Object>of(CommandMetadata.class, commandMetadata)); + CommandFactory commandFactory = new DefaultConstructorFactory(); + final C instance = (C) commandFactory.createInstance(command.getType()); + return configureInstance(instance, + command.getAllOptions(), + state.getParsedOptions(), + command.getArguments(), + state.getParsedArguments(), + command.getMetadataInjections(), + ImmutableMap., Object>of(CommandMetadata.class, commandMetadata)); } private void validate(ParseState state) diff --git a/src/main/java/io/airlift/airline/SuggestCommand.java b/src/main/java/io/airlift/airline/SuggestCommand.java index 71fab7137..bd75c778c 100644 --- a/src/main/java/io/airlift/airline/SuggestCommand.java +++ b/src/main/java/io/airlift/airline/SuggestCommand.java @@ -4,6 +4,8 @@ import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import io.airlift.airline.factory.CommandFactory; +import io.airlift.airline.factory.DefaultConstructorFactory; import io.airlift.airline.model.CommandGroupMetadata; import io.airlift.airline.model.CommandMetadata; import io.airlift.airline.model.GlobalMetadata; @@ -17,7 +19,7 @@ import java.util.concurrent.Callable; import static com.google.common.collect.Lists.newArrayList; -import static io.airlift.airline.ParserUtil.createInstance; +import static io.airlift.airline.ParserUtil.configureInstance; @Command(name = "suggest") public class SuggestCommand @@ -57,13 +59,15 @@ public Iterable generateSuggestions() bindings.put(CommandMetadata.class, state.getCommand()); } - Suggester suggester = createInstance(suggesterMetadata.getSuggesterClass(), - ImmutableList.of(), - null, - null, - null, - suggesterMetadata.getMetadataInjections(), - bindings.build()); + CommandFactory commandFactory = new DefaultConstructorFactory(); + final Suggester instance = commandFactory.createInstance(suggesterMetadata.getSuggesterClass()); + Suggester suggester = configureInstance(instance, + ImmutableList.of(), + null, + null, + null, + suggesterMetadata.getMetadataInjections(), + bindings.build()); return suggester.suggest(); } diff --git a/src/main/java/io/airlift/airline/factory/CommandFactory.java b/src/main/java/io/airlift/airline/factory/CommandFactory.java new file mode 100644 index 000000000..08298ecb6 --- /dev/null +++ b/src/main/java/io/airlift/airline/factory/CommandFactory.java @@ -0,0 +1,5 @@ +package io.airlift.airline.factory; + +public interface CommandFactory { + T createInstance(Class instanceClass); +} diff --git a/src/main/java/io/airlift/airline/factory/DefaultConstructorFactory.java b/src/main/java/io/airlift/airline/factory/DefaultConstructorFactory.java new file mode 100644 index 000000000..a5e90ed66 --- /dev/null +++ b/src/main/java/io/airlift/airline/factory/DefaultConstructorFactory.java @@ -0,0 +1,18 @@ +package io.airlift.airline.factory; + +import io.airlift.airline.ParseException; + +public class DefaultConstructorFactory implements CommandFactory { + @Override + public T createInstance(Class type) { + if (type != null) { + try { + return type.getConstructor().newInstance(); + } + catch (Exception e) { + throw new ParseException(e, "Unable to create instance %s", type.getName()); + } + } + return null; + } +}