New Upstream Snapshot - airlift-airline

Ready changes

Summary

Merged new upstream version: 0.9+git20210608.1.1f640f8 (was: 0.7).

Resulting package

Built on 2022-11-08T03:31 (took 15m20s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-snapshots libairline-java

Lintian Result

Diff

diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 8b22676..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,17 +0,0 @@
-*.iml
-*.ipr
-*.iws
-/target
-pom.xml.versionsBackup
-/test-output
-atlassian-ide-plugin.xml
-.idea
-.DS_Store
-.classpath
-.project
-.settings
-.project
-temp-testng-customsuite.xml
-.externalToolBuilders
-*~
-.rvmrc
diff --git a/.travis.yml b/.travis.yml
index dff5f3a..ca04644 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1 +1,7 @@
 language: java
+
+dist: trusty
+
+jdk:
+  - oraclejdk8
+  - oraclejdk9
diff --git a/README.md b/README.md
index ba4fb09..677d4bf 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,21 @@
+# :warning: DEPRECATED :warning:
+
+This project is no longer maintained. We recommend
+[Airline 2](https://rvesse.github.io/airline/) or
+[Picocli](https://picocli.info/) as a replacement.
+
 Airline
 =======
 
 Airline is a Java annotation-based framework for parsing Git like command line structures.
 
-Latest release is 0.6, available from Maven Central.
+Latest release is 0.9, available from Maven Central.
 
 ```xml
 <dependency>
     <groupId>io.airlift</groupId>
     <artifactId>airline</artifactId>
-    <version>0.6</version>
+    <version>0.9</version>
 </dependency>
 ```
 
diff --git a/debian/changelog b/debian/changelog
index 7ada3e3..adcc382 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+airlift-airline (0.9+git20210608.1.1f640f8-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Tue, 08 Nov 2022 03:20:51 -0000
+
 airlift-airline (0.7-3) unstable; urgency=medium
 
   * Team upload.
diff --git a/pom.xml b/pom.xml
index a5b4e85..7e7ad9f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,12 +24,12 @@
     <parent>
         <groupId>io.airlift</groupId>
         <artifactId>airbase</artifactId>
-        <version>28</version>
+        <version>93</version>
     </parent>
 
     <artifactId>airline</artifactId>
     <packaging>jar</packaging>
-    <version>0.7</version>
+    <version>0.10-SNAPSHOT</version>
 
     <name>airline</name>
     <description>Java annotation-based framework for parsing Git like command line structures</description>
@@ -40,11 +40,11 @@
     <scm>
         <connection>scm:git:git@github.com:airlift/airline.git</connection>
         <url>http://github.com/airlift/airline/tree/master</url>
-      <tag>0.7</tag>
-  </scm>
+        <tag>HEAD</tag>
+    </scm>
 
     <properties>
-        <air.check.skip-findbugs>true</air.check.skip-findbugs>
+        <air.check.skip-spotbugs>true</air.check.skip-spotbugs>
         <air.check.skip-pmd>true</air.check.skip-pmd>
         <air.check.skip-license>true</air.check.skip-license>
     </properties>
@@ -57,7 +57,7 @@
 
         <dependency>
             <groupId>com.google.code.findbugs</groupId>
-            <artifactId>annotations</artifactId>
+            <artifactId>jsr305</artifactId>
         </dependency>
 
         <dependency>
@@ -71,5 +71,11 @@
             <artifactId>testng</artifactId>
             <scope>test</scope>
         </dependency>
+        
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git a/src/main/java/io/airlift/airline/Accessor.java b/src/main/java/io/airlift/airline/Accessor.java
index 9122be6..3c1193d 100644
--- a/src/main/java/io/airlift/airline/Accessor.java
+++ b/src/main/java/io/airlift/airline/Accessor.java
@@ -1,8 +1,5 @@
 package io.airlift.airline;
 
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 
@@ -18,6 +15,10 @@ import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.joining;
+
 public class Accessor
 {
     private final String name;
@@ -32,18 +33,12 @@ public class Accessor
 
     public Accessor(Iterable<Field> path)
     {
-        Preconditions.checkNotNull(path, "path is null");
-        Preconditions.checkArgument(!Iterables.isEmpty(path), "path is empty");
+        requireNonNull(path, "path is null");
+        checkArgument(!Iterables.isEmpty(path), "path is empty");
 
         this.path = ImmutableList.copyOf(path);
-        this.name = this.path.get(0).getDeclaringClass().getSimpleName() + "." + Joiner.on('.').join(Iterables.transform(this.path, new Function<Field, String>()
-        {
-            public String apply(Field field)
-            {
-                return field.getName();
-            }
-        }));
-
+        this.name = this.path.get(0).getDeclaringClass().getSimpleName() + "." +
+                this.path.stream().map(Field::getName).collect(joining("."));
 
         Field field = this.path.get(this.path.size() - 1);
         multiValued = Collection.class.isAssignableFrom(field.getType());
@@ -112,7 +107,6 @@ public class Accessor
                 throw new ParseException(e, "Error setting %s for argument %s", field.getName(), name);
             }
         }
-
     }
 
     @Override
diff --git a/src/main/java/io/airlift/airline/Arguments.java b/src/main/java/io/airlift/airline/Arguments.java
index 9a598f9..5a388a5 100644
--- a/src/main/java/io/airlift/airline/Arguments.java
+++ b/src/main/java/io/airlift/airline/Arguments.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -22,9 +22,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
 import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
-@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
-@Target({FIELD})
+@Retention(RUNTIME)
+@Target(FIELD)
 public @interface Arguments
 {
     /**
diff --git a/src/main/java/io/airlift/airline/Cli.java b/src/main/java/io/airlift/airline/Cli.java
index 13f7533..610b8c9 100644
--- a/src/main/java/io/airlift/airline/Cli.java
+++ b/src/main/java/io/airlift/airline/Cli.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -18,11 +18,9 @@
 
 package io.airlift.airline;
 
-import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 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;
@@ -30,18 +28,27 @@ import io.airlift.airline.model.GlobalMetadata;
 import io.airlift.airline.model.MetadataLoader;
 import io.airlift.airline.model.OptionMetadata;
 
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Maps.newHashMap;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.common.collect.Streams.stream;
 import static io.airlift.airline.ParserUtil.createInstance;
+import static io.airlift.airline.ParserUtil.injectOptions;
+import static io.airlift.airline.model.MetadataLoader.loadCommand;
+import static io.airlift.airline.model.MetadataLoader.loadCommandGroup;
+import static io.airlift.airline.model.MetadataLoader.loadCommands;
+import static java.util.Objects.requireNonNull;
 
 public class Cli<C>
 {
     public static <T> CliBuilder<T> builder(String name)
     {
-        Preconditions.checkNotNull(name, "name is null");
+        requireNonNull(name, "name is null");
         return new CliBuilder<T>(name);
     }
 
@@ -66,23 +73,25 @@ public class Cli<C>
             Iterable<Class<? extends C>> defaultGroupCommands,
             Iterable<GroupBuilder<C>> groups)
     {
-        Preconditions.checkNotNull(name, "name is null");
-        Preconditions.checkNotNull(typeConverter, "typeConverter is null");
+        requireNonNull(name, "name is null");
+        requireNonNull(typeConverter, "typeConverter is null");
 
         CommandMetadata defaultCommandMetadata = null;
         if (defaultCommand != null) {
-            defaultCommandMetadata = MetadataLoader.loadCommand(defaultCommand);
+            defaultCommandMetadata = loadCommand(defaultCommand);
         }
 
-        List<CommandMetadata> defaultCommandGroup = MetadataLoader.loadCommands(defaultGroupCommands);
+        List<CommandMetadata> defaultCommandGroup = loadCommands(defaultGroupCommands);
 
-        List<CommandGroupMetadata> commandGroups = ImmutableList.copyOf(Iterables.transform(groups, new Function<GroupBuilder<C>, CommandGroupMetadata>()
-        {
-            public CommandGroupMetadata apply(GroupBuilder<C> group)
-            {
-                return MetadataLoader.loadCommandGroup(group.name, group.description, MetadataLoader.loadCommand(group.defaultCommand), MetadataLoader.loadCommands(group.commands));
-            }
-        }));
+        List<CommandGroupMetadata> commandGroups = stream(groups)
+                .map(group -> loadCommandGroup(
+                        group.name,
+                        group.description,
+                        Optional.ofNullable(group.defaultCommand)
+                                .map(MetadataLoader::loadCommand)
+                                .orElse(null),
+                        loadCommands(group.commands)))
+                .collect(toImmutableList());
 
         this.metadata = MetadataLoader.loadGlobal(name, description, defaultCommandMetadata, defaultCommandGroup, commandGroups);
     }
@@ -96,11 +105,21 @@ public class Cli<C>
     {
         return parse(ImmutableList.copyOf(args));
     }
-    
+
     public C parse(Iterable<String> args)
     {
-        Preconditions.checkNotNull(args, "args is null");
-        
+        return parse(new DefaultCommandFactory<C>(), args);
+    }
+
+    public C parse(CommandFactory<C> commandFactory, String... args)
+    {
+        return parse(commandFactory, ImmutableList.copyOf(args));
+    }
+
+    public C parse(CommandFactory<C> commandFactory, Iterable<String> args)
+    {
+        requireNonNull(args, "args is null");
+
         Parser parser = new Parser();
         ParseState state = parser.parse(metadata, args);
 
@@ -118,6 +137,36 @@ public class Cli<C>
         CommandMetadata command = state.getCommand();
 
         return createInstance(command.getType(),
+                command.getAllOptions(),
+                state.getParsedOptions(),
+                command.getArguments(),
+                state.getParsedArguments(),
+                command.getMetadataInjections(),
+                ImmutableMap.<Class<?>, Object>of(GlobalMetadata.class, metadata),
+                commandFactory);
+    }
+
+    public C parse(C commandInstance, String... args)
+    {
+        requireNonNull(args, "args is null");
+
+        Parser parser = new Parser();
+        ParseState state = parser.parse(metadata, args);
+
+        if (state.getCommand() == null) {
+            if (state.getGroup() != null) {
+                state = state.withCommand(state.getGroup().getDefaultCommand());
+            }
+            else {
+                state = state.withCommand(metadata.getDefaultCommand());
+            }
+        }
+
+        validate(state);
+
+        CommandMetadata command = state.getCommand();
+
+        return injectOptions(commandInstance,
                 command.getAllOptions(),
                 state.getParsedOptions(),
                 command.getArguments(),
@@ -125,7 +174,7 @@ public class Cli<C>
                 command.getMetadataInjections(),
                 ImmutableMap.<Class<?>, Object>of(GlobalMetadata.class, metadata));
     }
-    
+
     private void validate(ParseState state)
     {
         CommandMetadata command = state.getCommand();
@@ -143,7 +192,7 @@ public class Cli<C>
         if (state.getParsedArguments().isEmpty() && arguments != null && arguments.isRequired()) {
             throw new ParseArgumentsMissingException(arguments.getTitle());
         }
-        
+
         if (!state.getUnparsedInput().isEmpty()) {
             throw new ParseArgumentsUnexpectedException(state.getUnparsedInput());
         }
@@ -170,34 +219,34 @@ public class Cli<C>
         protected TypeConverter typeConverter = new TypeConverter();
         protected String optionSeparators;
         private Class<? extends C> defaultCommand;
-        private final List<Class<? extends C>> defaultCommandGroupCommands = newArrayList();
-        protected final Map<String, GroupBuilder<C>> groups = newHashMap();
+        private final List<Class<? extends C>> defaultCommandGroupCommands = new ArrayList<>();
+        protected final Map<String, GroupBuilder<C>> groups = new HashMap<>();
 
         public CliBuilder(String name)
         {
-            Preconditions.checkNotNull(name, "name is null");
-            Preconditions.checkArgument(!name.isEmpty(), "name is empty");
+            requireNonNull(name, "name is null");
+            checkArgument(!name.isEmpty(), "name is empty");
             this.name = name;
         }
 
         public CliBuilder<C> withDescription(String description)
         {
-            Preconditions.checkNotNull(description, "description is null");
-            Preconditions.checkArgument(!description.isEmpty(), "description is empty");
+            requireNonNull(description, "description is null");
+            checkArgument(!description.isEmpty(), "description is empty");
             this.description = description;
             return this;
         }
 
 //        public CliBuilder<C> withTypeConverter(TypeConverter typeConverter)
 //        {
-//            Preconditions.checkNotNull(typeConverter, "typeConverter is null");
+//            Preconditions.requireNonNull(typeConverter, "typeConverter is null");
 //            this.typeConverter = typeConverter;
 //            return this;
 //        }
 
 //        public CliBuilder<C> withOptionSeparators(String optionsSeparator)
 //        {
-//            Preconditions.checkNotNull(optionsSeparator, "optionsSeparator is null");
+//            Preconditions.requireNonNull(optionsSeparator, "optionsSeparator is null");
 //            this.optionSeparators = optionsSeparator;
 //            return this;
 //        }
@@ -214,7 +263,8 @@ public class Cli<C>
             return this;
         }
 
-        public CliBuilder<C> withCommands(Class<? extends C> command, Class<? extends C>... moreCommands)
+        @SafeVarargs
+        public final CliBuilder<C> withCommands(Class<? extends C> command, Class<? extends C>... moreCommands)
         {
             this.defaultCommandGroupCommands.add(command);
             this.defaultCommandGroupCommands.addAll(ImmutableList.copyOf(moreCommands));
@@ -229,8 +279,8 @@ public class Cli<C>
 
         public GroupBuilder<C> withGroup(String name)
         {
-            Preconditions.checkNotNull(name, "name is null");
-            Preconditions.checkArgument(!name.isEmpty(), "name is empty");
+            requireNonNull(name, "name is null");
+            checkArgument(!name.isEmpty(), "name is empty");
 
             if (groups.containsKey(name)) {
                 return groups.get(name);
@@ -250,21 +300,21 @@ public class Cli<C>
     public static class GroupBuilder<C>
     {
         private final String name;
-        private String description = null;
-        private Class<? extends C> defaultCommand = null;
+        private String description;
+        private Class<? extends C> defaultCommand;
 
-        private final List<Class<? extends C>> commands = newArrayList();
+        private final List<Class<? extends C>> commands = new ArrayList<>();
 
         private GroupBuilder(String name)
         {
-            Preconditions.checkNotNull(name, "name is null");
+            requireNonNull(name, "name is null");
             this.name = name;
         }
 
         public GroupBuilder<C> withDescription(String description)
         {
-            Preconditions.checkNotNull(description, "description is null");
-            Preconditions.checkArgument(!description.isEmpty(), "description is empty");
+            requireNonNull(description, "description is null");
+            checkArgument(!description.isEmpty(), "description is empty");
             Preconditions.checkState(this.description == null, "description is already set");
             this.description = description;
             return this;
@@ -272,7 +322,7 @@ public class Cli<C>
 
         public GroupBuilder<C> withDefaultCommand(Class<? extends C> defaultCommand)
         {
-            Preconditions.checkNotNull(defaultCommand, "defaultCommand is null");
+            requireNonNull(defaultCommand, "defaultCommand is null");
             Preconditions.checkState(this.defaultCommand == null, "defaultCommand is already set");
             this.defaultCommand = defaultCommand;
             return this;
@@ -280,12 +330,13 @@ public class Cli<C>
 
         public GroupBuilder<C> withCommand(Class<? extends C> command)
         {
-            Preconditions.checkNotNull(command, "command is null");
+            requireNonNull(command, "command is null");
             commands.add(command);
             return this;
         }
 
-        public GroupBuilder<C> withCommands(Class<? extends C> command, Class<? extends C>... moreCommands)
+        @SafeVarargs
+        public final GroupBuilder<C> withCommands(Class<? extends C> command, Class<? extends C>... moreCommands)
         {
             this.commands.add(command);
             this.commands.addAll(ImmutableList.copyOf(moreCommands));
diff --git a/src/main/java/io/airlift/airline/Command.java b/src/main/java/io/airlift/airline/Command.java
index ce68a8d..038114b 100644
--- a/src/main/java/io/airlift/airline/Command.java
+++ b/src/main/java/io/airlift/airline/Command.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
diff --git a/src/main/java/io/airlift/airline/CommandFactory.java b/src/main/java/io/airlift/airline/CommandFactory.java
new file mode 100644
index 0000000..e84632e
--- /dev/null
+++ b/src/main/java/io/airlift/airline/CommandFactory.java
@@ -0,0 +1,6 @@
+package io.airlift.airline;
+
+public interface CommandFactory<T>
+{
+    T createInstance(Class<?> type);
+}
diff --git a/src/main/java/io/airlift/airline/CommandGroupUsage.java b/src/main/java/io/airlift/airline/CommandGroupUsage.java
index 6397a07..29581a6 100644
--- a/src/main/java/io/airlift/airline/CommandGroupUsage.java
+++ b/src/main/java/io/airlift/airline/CommandGroupUsage.java
@@ -1,17 +1,18 @@
 package io.airlift.airline;
 
-import com.google.common.base.Preconditions;
 import io.airlift.airline.model.CommandGroupMetadata;
 import io.airlift.airline.model.CommandMetadata;
 import io.airlift.airline.model.GlobalMetadata;
 import io.airlift.airline.model.OptionMetadata;
 
 import javax.annotation.Nullable;
+
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
-import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.base.Preconditions.checkArgument;
 import static io.airlift.airline.UsageHelper.DEFAULT_COMMAND_COMPARATOR;
 import static io.airlift.airline.UsageHelper.DEFAULT_OPTION_COMPARATOR;
 
@@ -39,7 +40,7 @@ public class CommandGroupUsage
 
     public CommandGroupUsage(int columnSize, boolean hideGlobalOptions, @Nullable Comparator<? super OptionMetadata> optionComparator)
     {
-        Preconditions.checkArgument(columnSize > 0, "columnSize must be greater than 0");
+        checkArgument(columnSize > 0, "columnSize must be greater than 0");
         this.columnSize = columnSize;
         this.hideGlobalOptions = hideGlobalOptions;
         this.optionComparator = optionComparator;
@@ -84,7 +85,7 @@ public class CommandGroupUsage
         out.append("SYNOPSIS").newline();
         UsagePrinter synopsis = out.newIndentedPrinter(8).newPrinterWithHangingIndent(8);
 
-        List<CommandMetadata> commands = newArrayList(group.getCommands());
+        List<CommandMetadata> commands = new ArrayList<>(group.getCommands());
         Collections.sort(commands, commandComparator);
 
         if (group.getDefaultCommand() != null) {
@@ -114,7 +115,7 @@ public class CommandGroupUsage
         //
         // OPTIONS
         //
-        List<OptionMetadata> options = newArrayList();
+        List<OptionMetadata> options = new ArrayList<>();
         options.addAll(group.getOptions());
         if (global != null && !hideGlobalOptions) {
             options.addAll(global.getOptions());
diff --git a/src/main/java/io/airlift/airline/CommandSuggester.java b/src/main/java/io/airlift/airline/CommandSuggester.java
index 6514ae1..14511ad 100644
--- a/src/main/java/io/airlift/airline/CommandSuggester.java
+++ b/src/main/java/io/airlift/airline/CommandSuggester.java
@@ -19,7 +19,7 @@ public class CommandSuggester
     public Iterable<String> suggest()
     {
         ImmutableList.Builder<String> suggestions = ImmutableList.<String>builder()
-                .addAll(concat(transform(command.getCommandOptions(), OptionMetadata.optionsGetter())));
+                .addAll(concat(transform(command.getCommandOptions(), OptionMetadata::getOptions)));
 
         if (command.getArguments() != null) {
             suggestions.add("--");
diff --git a/src/main/java/io/airlift/airline/CommandUsage.java b/src/main/java/io/airlift/airline/CommandUsage.java
index d053bd6..f9e59c8 100644
--- a/src/main/java/io/airlift/airline/CommandUsage.java
+++ b/src/main/java/io/airlift/airline/CommandUsage.java
@@ -1,17 +1,17 @@
 package io.airlift.airline;
 
-import com.google.common.base.Preconditions;
 import io.airlift.airline.model.ArgumentsMetadata;
 import io.airlift.airline.model.CommandMetadata;
 import io.airlift.airline.model.OptionMetadata;
 
 import javax.annotation.Nullable;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
-import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.base.Preconditions.checkArgument;
 import static io.airlift.airline.UsageHelper.DEFAULT_OPTION_COMPARATOR;
 import static io.airlift.airline.UsageHelper.toSynopsisUsage;
 
@@ -32,7 +32,7 @@ public class CommandUsage
 
     public CommandUsage(int columnSize, @Nullable Comparator<? super OptionMetadata> optionComparator)
     {
-        Preconditions.checkArgument(columnSize > 0, "columnSize must be greater than 0");
+        checkArgument(columnSize > 0, "columnSize must be greater than 0");
         this.columnSize = columnSize;
         this.optionComparator = optionComparator;
     }
@@ -76,7 +76,7 @@ public class CommandUsage
         //
         out.append("SYNOPSIS").newline();
         UsagePrinter synopsis = out.newIndentedPrinter(8).newPrinterWithHangingIndent(8);
-        List<OptionMetadata> options = newArrayList();
+        List<OptionMetadata> options = new ArrayList<>();
         if (programName != null) {
             synopsis.append(programName).appendWords(toSynopsisUsage(sortOptions(command.getGlobalOptions())));
             options.addAll(command.getGlobalOptions());
@@ -141,7 +141,6 @@ public class CommandUsage
                 descriptionPrinter.newline();
             }
         }
-
     }
 
     private List<OptionMetadata> sortOptions(List<OptionMetadata> options)
diff --git a/src/main/java/io/airlift/airline/DefaultCommandFactory.java b/src/main/java/io/airlift/airline/DefaultCommandFactory.java
new file mode 100644
index 0000000..c49f99a
--- /dev/null
+++ b/src/main/java/io/airlift/airline/DefaultCommandFactory.java
@@ -0,0 +1,12 @@
+package io.airlift.airline;
+
+public class DefaultCommandFactory<T>
+        implements CommandFactory<T>
+{
+    @SuppressWarnings("unchecked")
+    @Override
+    public T createInstance(Class<?> type)
+    {
+        return (T) ParserUtil.createInstance(type);
+    }
+}
diff --git a/src/main/java/io/airlift/airline/GlobalSuggester.java b/src/main/java/io/airlift/airline/GlobalSuggester.java
index b670cdc..391ad80 100644
--- a/src/main/java/io/airlift/airline/GlobalSuggester.java
+++ b/src/main/java/io/airlift/airline/GlobalSuggester.java
@@ -11,7 +11,7 @@ import static com.google.common.collect.Iterables.concat;
 import static com.google.common.collect.Iterables.transform;
 
 public class GlobalSuggester
-    implements Suggester
+        implements Suggester
 {
     @Inject
     public GlobalMetadata metadata;
@@ -20,9 +20,8 @@ public class GlobalSuggester
     public Iterable<String> suggest()
     {
         return concat(
-                transform(metadata.getCommandGroups(), CommandGroupMetadata.nameGetter()),
-                transform(metadata.getDefaultGroupCommands(), CommandMetadata.nameGetter()),
-                concat(transform(metadata.getOptions(), OptionMetadata.optionsGetter()))
-        );
+                transform(metadata.getCommandGroups(), CommandGroupMetadata::getName),
+                transform(metadata.getDefaultGroupCommands(), CommandMetadata::getName),
+                concat(transform(metadata.getOptions(), OptionMetadata::getOptions)));
     }
 }
diff --git a/src/main/java/io/airlift/airline/GlobalUsage.java b/src/main/java/io/airlift/airline/GlobalUsage.java
index 221532e..197d6e2 100644
--- a/src/main/java/io/airlift/airline/GlobalUsage.java
+++ b/src/main/java/io/airlift/airline/GlobalUsage.java
@@ -1,17 +1,18 @@
 package io.airlift.airline;
 
-import com.google.common.base.Preconditions;
 import io.airlift.airline.model.CommandGroupMetadata;
 import io.airlift.airline.model.CommandMetadata;
 import io.airlift.airline.model.GlobalMetadata;
 import io.airlift.airline.model.OptionMetadata;
 
 import javax.annotation.Nullable;
+
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
-import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.base.Preconditions.checkArgument;
 import static io.airlift.airline.UsageHelper.DEFAULT_OPTION_COMPARATOR;
 
 public class GlobalUsage
@@ -31,7 +32,7 @@ public class GlobalUsage
 
     public GlobalUsage(int columnSize, @Nullable Comparator<? super OptionMetadata> optionComparator)
     {
-        Preconditions.checkArgument(columnSize > 0, "columnSize must be greater than 0");
+        checkArgument(columnSize > 0, "columnSize must be greater than 0");
         this.columnSize = columnSize;
         this.optionComparator = optionComparator;
     }
@@ -82,7 +83,7 @@ public class GlobalUsage
         //
         // OPTIONS
         //
-        List<OptionMetadata> options = newArrayList(global.getOptions());
+        List<OptionMetadata> options = new ArrayList<>(global.getOptions());
         if (options.size() > 0) {
             if (optionComparator != null) {
                 Collections.sort(options, optionComparator);
diff --git a/src/main/java/io/airlift/airline/GlobalUsageSummary.java b/src/main/java/io/airlift/airline/GlobalUsageSummary.java
index d273446..ac1aa68 100644
--- a/src/main/java/io/airlift/airline/GlobalUsageSummary.java
+++ b/src/main/java/io/airlift/airline/GlobalUsageSummary.java
@@ -1,23 +1,18 @@
 package io.airlift.airline;
 
-import com.google.common.base.Function;
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
 import io.airlift.airline.model.CommandGroupMetadata;
 import io.airlift.airline.model.CommandMetadata;
 import io.airlift.airline.model.GlobalMetadata;
-import io.airlift.airline.model.OptionMetadata;
 
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
+import java.util.TreeMap;
 
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Maps.newTreeMap;
-import static io.airlift.airline.UsageHelper.toUsage;
+import static com.google.common.base.MoreObjects.firstNonNull;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.ImmutableList.toImmutableList;
+import static java.util.stream.Collectors.toList;
 
 public class GlobalUsageSummary
 {
@@ -30,7 +25,7 @@ public class GlobalUsageSummary
 
     public GlobalUsageSummary(int columnSize)
     {
-        Preconditions.checkArgument(columnSize > 0, "columnSize must be greater than 0");
+        checkArgument(columnSize > 0, "columnSize must be greater than 0");
         this.columnSize = columnSize;
     }
 
@@ -59,17 +54,11 @@ public class GlobalUsageSummary
         //
 
         // build arguments
-        List<String> commandArguments = newArrayList();
-        commandArguments.addAll(Collections2.transform(global.getOptions(), new Function<OptionMetadata, String>()
-        {
-            public String apply(OptionMetadata option)
-            {
-                if (option.isHidden()) {
-                    return null;
-                }
-                return toUsage(option);
-            }
-        }));
+        List<String> commandArguments = global.getOptions().stream()
+                .filter(option -> !option.isHidden())
+                .map(UsageHelper::toUsage)
+                .collect(toImmutableList());
+
         out.newPrinterWithHangingIndent(8)
                 .append("usage:")
                 .append(global.getName())
@@ -82,7 +71,7 @@ public class GlobalUsageSummary
         // Common commands
         //
 
-        Map<String, String> commands = newTreeMap();
+        Map<String, String> commands = new TreeMap<>();
         for (CommandMetadata commandMetadata : global.getDefaultGroupCommands()) {
             if (!commandMetadata.isHidden()) {
                 commands.put(commandMetadata.getName(), commandMetadata.getDescription());
@@ -93,13 +82,9 @@ public class GlobalUsageSummary
         }
 
         out.append("The most commonly used ").append(global.getName()).append(" commands are:").newline();
-        out.newIndentedPrinter(4).appendTable(Iterables.transform(commands.entrySet(), new Function<Entry<String, String>, Iterable<String>>()
-        {
-            public Iterable<String> apply(Entry<String, String> entry)
-            {
-                return ImmutableList.of(entry.getKey(), Objects.firstNonNull(entry.getValue(), ""));
-            }
-        }));
+        out.newIndentedPrinter(4).appendTable(commands.entrySet().stream()
+                .map(entry -> ImmutableList.of(entry.getKey(), firstNonNull(entry.getValue(), "")))
+                .collect(toList()));
         out.newline();
         out.append("See").append("'" + global.getName()).append("help <command>' for more information on a specific command.").newline();
     }
diff --git a/src/main/java/io/airlift/airline/GroupSuggester.java b/src/main/java/io/airlift/airline/GroupSuggester.java
index 4758f63..85279d4 100644
--- a/src/main/java/io/airlift/airline/GroupSuggester.java
+++ b/src/main/java/io/airlift/airline/GroupSuggester.java
@@ -19,8 +19,7 @@ public class GroupSuggester
     public Iterable<String> suggest()
     {
         return concat(
-                transform(group.getCommands(), CommandMetadata.nameGetter()),
-                concat(transform(group.getOptions(), OptionMetadata.optionsGetter()))
-        );
+                transform(group.getCommands(), CommandMetadata::getName),
+                concat(transform(group.getOptions(), OptionMetadata::getOptions)));
     }
 }
diff --git a/src/main/java/io/airlift/airline/Help.java b/src/main/java/io/airlift/airline/Help.java
index 868651c..14cacea 100644
--- a/src/main/java/io/airlift/airline/Help.java
+++ b/src/main/java/io/airlift/airline/Help.java
@@ -5,19 +5,20 @@ import io.airlift.airline.model.CommandMetadata;
 import io.airlift.airline.model.GlobalMetadata;
 
 import javax.inject.Inject;
+
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Callable;
 
-import static com.google.common.collect.Lists.newArrayList;
-
 @Command(name = "help", description = "Display help information")
-public class Help implements Runnable, Callable<Void>
+public class Help
+        implements Runnable, Callable<Void>
 {
     @Inject
     public GlobalMetadata global;
 
     @Arguments
-    public List<String> command = newArrayList();
+    public List<String> command = new ArrayList<>();
 
     @Override
     public void run()
diff --git a/src/main/java/io/airlift/airline/Option.java b/src/main/java/io/airlift/airline/Option.java
index 1188fad..d721b34 100644
--- a/src/main/java/io/airlift/airline/Option.java
+++ b/src/main/java/io/airlift/airline/Option.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -22,9 +22,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
 import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
-@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
-@Target({FIELD})
+@Retention(RUNTIME)
+@Target(FIELD)
 public @interface Option
 {
     /**
@@ -33,7 +34,7 @@ public @interface Option
     OptionType type() default OptionType.COMMAND;
 
     /**
-     * Name use to identify the option value in documentation and error messages.
+     * Name used to identify the option value in documentation and error messages.
      */
     String title() default "";
 
@@ -63,6 +64,5 @@ public @interface Option
      */
     boolean hidden() default false;
 
-    
     String[] allowedValues() default {};
 }
diff --git a/src/main/java/io/airlift/airline/ParseArgumentsMissingException.java b/src/main/java/io/airlift/airline/ParseArgumentsMissingException.java
index 5c59f3b..339713f 100644
--- a/src/main/java/io/airlift/airline/ParseArgumentsMissingException.java
+++ b/src/main/java/io/airlift/airline/ParseArgumentsMissingException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -18,7 +18,8 @@
 
 package io.airlift.airline;
 
-public class ParseArgumentsMissingException extends ParseException
+public class ParseArgumentsMissingException
+        extends ParseException
 {
     private final String argumentTitle;
 
diff --git a/src/main/java/io/airlift/airline/ParseArgumentsUnexpectedException.java b/src/main/java/io/airlift/airline/ParseArgumentsUnexpectedException.java
index fa347f5..3e0dc01 100644
--- a/src/main/java/io/airlift/airline/ParseArgumentsUnexpectedException.java
+++ b/src/main/java/io/airlift/airline/ParseArgumentsUnexpectedException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -22,7 +22,8 @@ import com.google.common.collect.ImmutableList;
 
 import java.util.List;
 
-public class ParseArgumentsUnexpectedException extends ParseException
+public class ParseArgumentsUnexpectedException
+        extends ParseException
 {
     private final List<String> unparsedInput;
 
diff --git a/src/main/java/io/airlift/airline/ParseCommandMissingException.java b/src/main/java/io/airlift/airline/ParseCommandMissingException.java
index 15ee712..4ae9675 100644
--- a/src/main/java/io/airlift/airline/ParseCommandMissingException.java
+++ b/src/main/java/io/airlift/airline/ParseCommandMissingException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -18,7 +18,8 @@
 
 package io.airlift.airline;
 
-public class ParseCommandMissingException extends ParseException
+public class ParseCommandMissingException
+        extends ParseException
 {
     ParseCommandMissingException()
     {
diff --git a/src/main/java/io/airlift/airline/ParseCommandUnrecognizedException.java b/src/main/java/io/airlift/airline/ParseCommandUnrecognizedException.java
index 72d9000..cd760f4 100644
--- a/src/main/java/io/airlift/airline/ParseCommandUnrecognizedException.java
+++ b/src/main/java/io/airlift/airline/ParseCommandUnrecognizedException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -22,7 +22,8 @@ import com.google.common.collect.ImmutableList;
 
 import java.util.List;
 
-public class ParseCommandUnrecognizedException extends ParseException
+public class ParseCommandUnrecognizedException
+        extends ParseException
 {
     private final List<String> unparsedInput;
 
diff --git a/src/main/java/io/airlift/airline/ParseException.java b/src/main/java/io/airlift/airline/ParseException.java
index 5b28f57..cd5d9b4 100644
--- a/src/main/java/io/airlift/airline/ParseException.java
+++ b/src/main/java/io/airlift/airline/ParseException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -18,14 +18,15 @@
 
 package io.airlift.airline;
 
-public class ParseException extends RuntimeException
+public class ParseException
+        extends RuntimeException
 {
     public ParseException(String string, Object... args)
     {
         super(String.format(string, args));
     }
 
-    public ParseException(Exception cause, String string, Object... args)
+    public ParseException(Throwable cause, String string, Object... args)
     {
         super(String.format(string, args), cause);
     }
diff --git a/src/main/java/io/airlift/airline/ParseOptionConversionException.java b/src/main/java/io/airlift/airline/ParseOptionConversionException.java
index b83ab1c..74ebfcc 100644
--- a/src/main/java/io/airlift/airline/ParseOptionConversionException.java
+++ b/src/main/java/io/airlift/airline/ParseOptionConversionException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -18,7 +18,8 @@
 
 package io.airlift.airline;
 
-public class ParseOptionConversionException extends ParseException
+public class ParseOptionConversionException
+        extends ParseException
 {
     private final String optionTitle;
     private final String value;
@@ -26,7 +27,12 @@ public class ParseOptionConversionException extends ParseException
 
     ParseOptionConversionException(String optionTitle, String value, String typeName)
     {
-        super("%s: can not convert \"%s\" to a %s", optionTitle, value, typeName);
+        this(optionTitle, value, typeName, null);
+    }
+
+    ParseOptionConversionException(String optionTitle, String value, String typeName, Throwable cause)
+    {
+        super(cause, "%s: can not convert \"%s\" to a %s", optionTitle, value, typeName);
         this.optionTitle = optionTitle;
         this.value = value;
         this.typeName = typeName;
diff --git a/src/main/java/io/airlift/airline/ParseOptionMissingException.java b/src/main/java/io/airlift/airline/ParseOptionMissingException.java
index c7b09ea..d4836b2 100644
--- a/src/main/java/io/airlift/airline/ParseOptionMissingException.java
+++ b/src/main/java/io/airlift/airline/ParseOptionMissingException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -18,7 +18,8 @@
 
 package io.airlift.airline;
 
-public class ParseOptionMissingException extends ParseException
+public class ParseOptionMissingException
+        extends ParseException
 {
     private final String optionTitle;
 
diff --git a/src/main/java/io/airlift/airline/ParseOptionMissingValueException.java b/src/main/java/io/airlift/airline/ParseOptionMissingValueException.java
index 05cfcbe..9cca5f6 100644
--- a/src/main/java/io/airlift/airline/ParseOptionMissingValueException.java
+++ b/src/main/java/io/airlift/airline/ParseOptionMissingValueException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -18,7 +18,8 @@
 
 package io.airlift.airline;
 
-public class ParseOptionMissingValueException extends ParseException
+public class ParseOptionMissingValueException
+        extends ParseException
 {
     private final String optionTitle;
 
diff --git a/src/main/java/io/airlift/airline/ParseState.java b/src/main/java/io/airlift/airline/ParseState.java
index c4eb965..d3dc4f4 100644
--- a/src/main/java/io/airlift/airline/ParseState.java
+++ b/src/main/java/io/airlift/airline/ParseState.java
@@ -18,7 +18,7 @@ public class ParseState
     private final ListMultimap<OptionMetadata, Object> parsedOptions;
     private final List<Object> parsedArguments;
     private final OptionMetadata currentOption;
-    private final List<String> unparsedInput; 
+    private final List<String> unparsedInput;
 
     ParseState(CommandGroupMetadata group,
             CommandMetadata command,
@@ -93,7 +93,6 @@ public class ParseState
         return new ParseState(group, command, parsedOptions, locationStack, newArguments, currentOption, unparsedInput);
     }
 
-
     public ParseState withUnparsedInput(String input)
     {
         ImmutableList<String> newUnparsedInput = ImmutableList.<String>builder()
diff --git a/src/main/java/io/airlift/airline/Parser.java b/src/main/java/io/airlift/airline/Parser.java
index 3686671..9b17a51 100644
--- a/src/main/java/io/airlift/airline/Parser.java
+++ b/src/main/java/io/airlift/airline/Parser.java
@@ -38,7 +38,7 @@ public class Parser
 
         // parse group
         if (tokens.hasNext()) {
-            CommandGroupMetadata group = find(metadata.getCommandGroups(), compose(equalTo(tokens.peek()), CommandGroupMetadata.nameGetter()), null);
+            CommandGroupMetadata group = find(metadata.getCommandGroups(), compose(equalTo(tokens.peek()), CommandGroupMetadata::getName), null);
             if (group != null) {
                 tokens.next();
                 state = state.withGroup(group).pushContext(Context.GROUP);
@@ -54,7 +54,7 @@ public class Parser
         }
 
         if (tokens.hasNext()) {
-            CommandMetadata command = find(expectedCommands, compose(equalTo(tokens.peek()), CommandMetadata.nameGetter()), null);
+            CommandMetadata command = find(expectedCommands, compose(equalTo(tokens.peek()), CommandMetadata::getName), null);
             if (command == null) {
                 while (tokens.hasNext()) {
                     state = state.withUnparsedInput(tokens.next());
@@ -279,5 +279,4 @@ public class Parser
         }
         return null;
     }
-
 }
diff --git a/src/main/java/io/airlift/airline/ParserUtil.java b/src/main/java/io/airlift/airline/ParserUtil.java
index 72d568b..8fafaa6 100644
--- a/src/main/java/io/airlift/airline/ParserUtil.java
+++ b/src/main/java/io/airlift/airline/ParserUtil.java
@@ -10,8 +10,10 @@ import java.util.Map;
 
 import static com.google.common.collect.Iterables.concat;
 
-public class ParserUtil
+public final class ParserUtil
 {
+    private ParserUtil() {}
+
     public static <T> T createInstance(Class<T> type)
     {
         if (type != null) {
@@ -31,15 +33,27 @@ public class ParserUtil
             ArgumentsMetadata arguments,
             Iterable<Object> parsedArguments,
             Iterable<Accessor> metadataInjection,
-            Map<Class<?>, Object> bindings)
+            Map<Class<?>, Object> bindings,
+            CommandFactory<T> commandFactory)
     {
         // create the command instance
-        T commandInstance = (T) ParserUtil.createInstance(type);
+        T commandInstance = commandFactory.createInstance(type);
+
+        return injectOptions(commandInstance, options, parsedOptions, arguments, parsedArguments, metadataInjection, bindings);
+    }
 
+    public static <T> T injectOptions(T commandInstance,
+            Iterable<OptionMetadata> options,
+            ListMultimap<OptionMetadata, Object> parsedOptions,
+            ArgumentsMetadata arguments,
+            Iterable<Object> parsedArguments,
+            Iterable<Accessor> metadataInjection,
+            Map<Class<?>, Object> bindings)
+    {
         // inject options
         for (OptionMetadata option : options) {
             List<?> values = parsedOptions.get(option);
-            if (option.getArity() > 1 && !values.isEmpty()) {
+            if (option.getArity() > 1 && values != null && !values.isEmpty()) {
                 // hack: flatten the collection
                 values = ImmutableList.copyOf(concat((Iterable<Iterable<Object>>) values));
             }
@@ -67,5 +81,4 @@ public class ParserUtil
 
         return commandInstance;
     }
-
 }
diff --git a/src/main/java/io/airlift/airline/SingleCommand.java b/src/main/java/io/airlift/airline/SingleCommand.java
index 8dc5d11..512e976 100644
--- a/src/main/java/io/airlift/airline/SingleCommand.java
+++ b/src/main/java/io/airlift/airline/SingleCommand.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -27,8 +27,8 @@ import io.airlift.airline.model.OptionMetadata;
 
 import java.util.List;
 
-import static com.google.common.base.Preconditions.checkNotNull;
 import static io.airlift.airline.ParserUtil.createInstance;
+import static java.util.Objects.requireNonNull;
 
 public class SingleCommand<C>
 {
@@ -41,7 +41,7 @@ public class SingleCommand<C>
 
     private SingleCommand(Class<C> command)
     {
-        checkNotNull(command, "command is null");
+        requireNonNull(command, "command is null");
 
         commandMetadata = MetadataLoader.loadCommand(command);
     }
@@ -55,11 +55,11 @@ public class SingleCommand<C>
     {
         return parse(ImmutableList.copyOf(args));
     }
-    
+
     public C parse(Iterable<String> args)
     {
-        checkNotNull(args, "args is null");
-        
+        requireNonNull(args, "args is null");
+
         Parser parser = new Parser();
         ParseState state = parser.parseCommand(commandMetadata, args);
         validate(state);
@@ -72,9 +72,10 @@ public class SingleCommand<C>
                 command.getArguments(),
                 state.getParsedArguments(),
                 command.getMetadataInjections(),
-                ImmutableMap.<Class<?>, Object>of(CommandMetadata.class, commandMetadata));
+                ImmutableMap.<Class<?>, Object>of(CommandMetadata.class, commandMetadata),
+                new DefaultCommandFactory<C>());
     }
-    
+
     private void validate(ParseState state)
     {
         CommandMetadata command = state.getCommand();
@@ -92,7 +93,7 @@ public class SingleCommand<C>
         if (state.getParsedArguments().isEmpty() && arguments != null && arguments.isRequired()) {
             throw new ParseArgumentsMissingException(arguments.getTitle());
         }
-        
+
         if (!state.getUnparsedInput().isEmpty()) {
             throw new ParseArgumentsUnexpectedException(state.getUnparsedInput());
         }
diff --git a/src/main/java/io/airlift/airline/SuggestCommand.java b/src/main/java/io/airlift/airline/SuggestCommand.java
index 71fab71..0bbe553 100644
--- a/src/main/java/io/airlift/airline/SuggestCommand.java
+++ b/src/main/java/io/airlift/airline/SuggestCommand.java
@@ -12,11 +12,12 @@ import io.airlift.airline.model.OptionMetadata;
 import io.airlift.airline.model.SuggesterMetadata;
 
 import javax.inject.Inject;
+
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
 
-import static com.google.common.collect.Lists.newArrayList;
 import static io.airlift.airline.ParserUtil.createInstance;
 
 @Command(name = "suggest")
@@ -33,7 +34,7 @@ public class SuggestCommand
     public GlobalMetadata metadata;
 
     @Arguments
-    public List<String> arguments = newArrayList();
+    public List<String> arguments = new ArrayList<>();
 
     @VisibleForTesting
     public Iterable<String> generateSuggestions()
@@ -63,7 +64,8 @@ public class SuggestCommand
                         null,
                         null,
                         suggesterMetadata.getMetadataInjections(),
-                        bindings.build());
+                        bindings.build(),
+                        new DefaultCommandFactory<Suggester>());
 
                 return suggester.suggest();
             }
diff --git a/src/main/java/io/airlift/airline/TypeConverter.java b/src/main/java/io/airlift/airline/TypeConverter.java
index ae4543f..fe0261e 100644
--- a/src/main/java/io/airlift/airline/TypeConverter.java
+++ b/src/main/java/io/airlift/airline/TypeConverter.java
@@ -1,10 +1,11 @@
 package io.airlift.airline;
 
-import com.google.common.base.Preconditions;
-
 import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
+import static java.util.Objects.requireNonNull;
+
 public class TypeConverter
 {
     public static TypeConverter newInstance()
@@ -14,9 +15,9 @@ public class TypeConverter
 
     public Object convert(String name, Class<?> type, String value)
     {
-        Preconditions.checkNotNull(name, "name is null");
-        Preconditions.checkNotNull(type, "type is null");
-        Preconditions.checkNotNull(value, "value is null");
+        requireNonNull(name, "name is null");
+        requireNonNull(type, "type is null");
+        requireNonNull(value, "value is null");
 
         try {
             if (String.class.isAssignableFrom(type)) {
@@ -53,7 +54,11 @@ public class TypeConverter
             if (valueOf.getReturnType().isAssignableFrom(type)) {
                 return valueOf.invoke(null, value);
             }
-        } catch (Throwable ignored) {
+        }
+        catch (InvocationTargetException ex) {
+            throw new ParseOptionConversionException(name, value, type.getSimpleName(), ex.getTargetException());
+        }
+        catch (IllegalAccessException | NoSuchMethodException ignored) {
         }
 
         // Look for a static valueOf(String) method (this covers enums which have a valueOf method)
@@ -63,7 +68,10 @@ public class TypeConverter
                 return valueOf.invoke(null, value);
             }
         }
-        catch (Throwable ignored) {
+        catch (InvocationTargetException ex) {
+            throw new ParseOptionConversionException(name, value, type.getSimpleName(), ex.getTargetException());
+        }
+        catch (IllegalAccessException | NoSuchMethodException ignored) {
         }
 
         // Look for a constructor taking a string
@@ -71,7 +79,10 @@ public class TypeConverter
             Constructor<?> constructor = type.getConstructor(String.class);
             return constructor.newInstance(value);
         }
-        catch (Throwable ignored) {
+        catch (InvocationTargetException ex) {
+            throw new ParseOptionConversionException(name, value, type.getSimpleName(), ex.getTargetException());
+        }
+        catch (IllegalAccessException | InstantiationException | NoSuchMethodException ignored) {
         }
 
         throw new ParseOptionConversionException(name, value, type.getSimpleName());
diff --git a/src/main/java/io/airlift/airline/UsageHelper.java b/src/main/java/io/airlift/airline/UsageHelper.java
index 03ee79c..814f44c 100644
--- a/src/main/java/io/airlift/airline/UsageHelper.java
+++ b/src/main/java/io/airlift/airline/UsageHelper.java
@@ -1,25 +1,21 @@
 package io.airlift.airline;
 
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
 import com.google.common.collect.ComparisonChain;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
 import io.airlift.airline.model.ArgumentsMetadata;
 import io.airlift.airline.model.CommandMetadata;
 import io.airlift.airline.model.OptionMetadata;
 
-import javax.annotation.Nullable;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Set;
 
-import static com.google.common.collect.Iterables.filter;
-import static com.google.common.collect.Iterables.transform;
-import static io.airlift.airline.model.OptionMetadata.isHiddenPredicate;
+import static com.google.common.collect.ImmutableList.toImmutableList;
+import static java.util.stream.Collectors.joining;
 
-public class UsageHelper
+public final class UsageHelper
 {
+    private UsageHelper() {}
+
     public static final Comparator<OptionMetadata> DEFAULT_OPTION_COMPARATOR = new Comparator<OptionMetadata>()
     {
         @Override
@@ -53,34 +49,21 @@ public class UsageHelper
 
     public static String toDescription(OptionMetadata option)
     {
-        Set<String> options = option.getOptions();
-        StringBuilder stringBuilder = new StringBuilder();
-
-        final String argumentString;
-        if (option.getArity() > 0) {
-            argumentString = Joiner.on(" ").join(Lists.transform(ImmutableList.of(option.getTitle()), new Function<String, String>()
-            {
-                public String apply(@Nullable String argument)
-                {
-                    return "<" + argument + ">";
-                }
-            }));
-        } else {
-            argumentString = null;
-        }
-
-        Joiner.on(", ").appendTo(stringBuilder, transform(options, new Function<String, String>()
-        {
-            public String apply(@Nullable String option)
-            {
-                if (argumentString != null) {
-                    return option + " " + argumentString;
-                }
-                return option;
-            }
-        }));
+        return optionString(option, ", ");
+    }
 
-        return stringBuilder.toString();
+    private static String optionString(OptionMetadata option, String delimiter)
+    {
+        String argument = (option.getArity() > 0) ? ("<" + option.getTitle() + ">") : null;
+
+        return option.getOptions().stream()
+                .map(value -> {
+                    if (argument != null) {
+                        return value + " " + argument;
+                    }
+                    return value;
+                })
+                .collect(joining(delimiter));
     }
 
     public static String toDescription(ArgumentsMetadata arguments)
@@ -90,7 +73,6 @@ public class UsageHelper
         }
 
         return "<" + arguments.getTitle() + ">";
-
     }
 
     public static String toUsage(OptionMetadata option)
@@ -106,32 +88,7 @@ public class UsageHelper
             stringBuilder.append('(');
         }
 
-        final String argumentString;
-        if (option.getArity() > 0) {
-            argumentString = Joiner.on(" ").join(transform(ImmutableList.of(option.getTitle()), new Function<String, String>()
-            {
-                public String apply(@Nullable String argument)
-                {
-                    return "<" + argument + ">";
-                }
-            }));
-        }
-        else {
-            argumentString = null;
-        }
-
-        Joiner.on(" | ").appendTo(stringBuilder, transform(options, new Function<String, String>()
-        {
-            public String apply(@Nullable String option)
-            {
-                if (argumentString != null) {
-                    return option + " " + argumentString;
-                }
-                else {
-                    return option;
-                }
-            }
-        }));
+        stringBuilder.append(optionString(option, " | "));
 
         if (options.size() > 1) {
             stringBuilder.append(')');
@@ -173,12 +130,9 @@ public class UsageHelper
 
     public static List<String> toSynopsisUsage(List<OptionMetadata> options)
     {
-        return ImmutableList.copyOf(transform(filter(options, isHiddenPredicate()), new Function<OptionMetadata, String>()
-        {
-            public String apply(OptionMetadata option)
-            {
-                return toUsage(option);
-            }
-        }));
+        return options.stream()
+                .filter(input -> !input.isHidden())
+                .map(UsageHelper::toUsage)
+                .collect(toImmutableList());
     }
 }
diff --git a/src/main/java/io/airlift/airline/UsagePrinter.java b/src/main/java/io/airlift/airline/UsagePrinter.java
index 4c674ae..c588328 100644
--- a/src/main/java/io/airlift/airline/UsagePrinter.java
+++ b/src/main/java/io/airlift/airline/UsagePrinter.java
@@ -2,11 +2,10 @@ package io.airlift.airline;
 
 import com.google.common.base.Splitter;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import static com.google.common.collect.Lists.newArrayList;
-
 public class UsagePrinter
 {
     private final StringBuilder out;
@@ -53,7 +52,7 @@ public class UsagePrinter
 
     public UsagePrinter appendTable(Iterable<? extends Iterable<String>> table)
     {
-        List<Integer> columnSizes = newArrayList();
+        List<Integer> columnSizes = new ArrayList<>();
         for (Iterable<String> row : table) {
             int column = 0;
             for (String value : row) {
diff --git a/src/main/java/io/airlift/airline/model/ArgumentsMetadata.java b/src/main/java/io/airlift/airline/model/ArgumentsMetadata.java
index a5487e1..a6d26c2 100644
--- a/src/main/java/io/airlift/airline/model/ArgumentsMetadata.java
+++ b/src/main/java/io/airlift/airline/model/ArgumentsMetadata.java
@@ -1,14 +1,15 @@
 package io.airlift.airline.model;
 
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import io.airlift.airline.Accessor;
 
 import java.lang.reflect.Field;
+import java.util.HashSet;
 import java.util.Set;
 
-import static com.google.common.collect.Sets.newHashSet;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
 
 public class ArgumentsMetadata
 {
@@ -20,9 +21,9 @@ public class ArgumentsMetadata
 
     public ArgumentsMetadata(String title, String description, String usage, boolean required, Iterable<Field> path)
     {
-        Preconditions.checkNotNull(title, "title is null");
-        Preconditions.checkNotNull(path, "path is null");
-        Preconditions.checkArgument(!Iterables.isEmpty(path), "path is empty");
+        requireNonNull(title, "title is null");
+        requireNonNull(path, "path is null");
+        checkArgument(!Iterables.isEmpty(path), "path is empty");
 
         this.title = title;
         this.description = description;
@@ -33,8 +34,8 @@ public class ArgumentsMetadata
 
     public ArgumentsMetadata(Iterable<ArgumentsMetadata> arguments)
     {
-        Preconditions.checkNotNull(arguments, "arguments is null");
-        Preconditions.checkArgument(!Iterables.isEmpty(arguments), "arguments is empty");
+        requireNonNull(arguments, "arguments is null");
+        checkArgument(!Iterables.isEmpty(arguments), "arguments is empty");
 
         ArgumentsMetadata first = arguments.iterator().next();
 
@@ -43,9 +44,9 @@ public class ArgumentsMetadata
         this.usage = first.usage;
         this.required = first.required;
 
-        Set<Accessor> accessors = newHashSet();
+        Set<Accessor> accessors = new HashSet<>();
         for (ArgumentsMetadata other : arguments) {
-            Preconditions.checkArgument(first.equals(other),
+            checkArgument(first.equals(other),
                     "Conflicting arguments definitions: %s, %s", first, other);
 
             accessors.addAll(other.getAccessors());
diff --git a/src/main/java/io/airlift/airline/model/CommandGroupMetadata.java b/src/main/java/io/airlift/airline/model/CommandGroupMetadata.java
index a7a7784..9028923 100644
--- a/src/main/java/io/airlift/airline/model/CommandGroupMetadata.java
+++ b/src/main/java/io/airlift/airline/model/CommandGroupMetadata.java
@@ -1,6 +1,5 @@
 package io.airlift.airline.model;
 
-import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 
 import java.util.List;
@@ -60,15 +59,4 @@ public class CommandGroupMetadata
         sb.append('}');
         return sb.toString();
     }
-
-    public static Function<CommandGroupMetadata, String> nameGetter()
-    {
-        return new Function<CommandGroupMetadata, String>()
-        {
-            public String apply(CommandGroupMetadata input)
-            {
-                return input.getName();
-            }
-        };
-    }
 }
diff --git a/src/main/java/io/airlift/airline/model/CommandMetadata.java b/src/main/java/io/airlift/airline/model/CommandMetadata.java
index 5cf95eb..ea01c76 100644
--- a/src/main/java/io/airlift/airline/model/CommandMetadata.java
+++ b/src/main/java/io/airlift/airline/model/CommandMetadata.java
@@ -1,6 +1,5 @@
 package io.airlift.airline.model;
 
-import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 import io.airlift.airline.Accessor;
 
@@ -56,7 +55,6 @@ public class CommandMetadata
     public List<OptionMetadata> getAllOptions()
     {
         return ImmutableList.<OptionMetadata>builder().addAll(globalOptions).addAll(groupOptions).addAll(commandOptions).build();
-
     }
 
     public List<OptionMetadata> getGlobalOptions()
@@ -105,15 +103,4 @@ public class CommandMetadata
         sb.append('}');
         return sb.toString();
     }
-
-    public static Function<CommandMetadata, String> nameGetter()
-    {
-        return new Function<CommandMetadata, String>()
-        {
-            public String apply(CommandMetadata input)
-            {
-                return input.getName();
-            }
-        };
-    }
 }
diff --git a/src/main/java/io/airlift/airline/model/MetadataLoader.java b/src/main/java/io/airlift/airline/model/MetadataLoader.java
index bd27347..e8c7120 100644
--- a/src/main/java/io/airlift/airline/model/MetadataLoader.java
+++ b/src/main/java/io/airlift/airline/model/MetadataLoader.java
@@ -1,7 +1,5 @@
 package io.airlift.airline.model;
 
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
@@ -13,19 +11,23 @@ import io.airlift.airline.Option;
 import io.airlift.airline.OptionType;
 import io.airlift.airline.Suggester;
 
-import javax.annotation.Nullable;
 import javax.inject.Inject;
+
 import java.lang.reflect.Field;
-import java.util.Collection;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import static com.google.common.collect.Iterables.transform;
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Maps.newHashMap;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.common.collect.Streams.stream;
+import static java.util.Objects.requireNonNull;
 
-public class MetadataLoader
+public final class MetadataLoader
 {
+    private MetadataLoader() {}
+
     public static GlobalMetadata loadGlobal(String name,
             String description,
             CommandMetadata defaultCommand,
@@ -63,22 +65,19 @@ public class MetadataLoader
 
     public static <T> ImmutableList<CommandMetadata> loadCommands(Iterable<Class<? extends T>> defaultCommands)
     {
-        return ImmutableList.copyOf(Iterables.transform(defaultCommands, new Function<Class<?>, CommandMetadata>()
-        {
-            public CommandMetadata apply(Class<?> commandType)
-            {
-                return loadCommand(commandType);
-            }
-        }));
+        return stream(defaultCommands)
+                .map(MetadataLoader::loadCommand)
+                .collect(toImmutableList());
     }
 
     public static CommandMetadata loadCommand(Class<?> commandType)
     {
+        requireNonNull(commandType, "commandType is null");
         Command command = null;
         for (Class<?> cls = commandType; command == null && !Object.class.equals(cls); cls = cls.getSuperclass()) {
             command = cls.getAnnotation(Command.class);
         }
-        Preconditions.checkArgument(command != null, "Command %s is not annotated with @Command", commandType.getName());
+        checkArgument(command != null, "Command %s is not annotated with @Command", commandType.getName());
         String name = command.name();
         String description = command.description().isEmpty() ? null : command.description();
         boolean hidden = command.hidden();
@@ -96,7 +95,6 @@ public class MetadataLoader
                 commandType);
 
         return commandMetadata;
-
     }
 
     public static SuggesterMetadata loadSuggester(Class<? extends Suggester> suggesterClass)
@@ -126,7 +124,8 @@ public class MetadataLoader
                             field.getType().equals(CommandGroupMetadata.class) ||
                             field.getType().equals(CommandMetadata.class)) {
                         injectionMetadata.metadataInjections.add(new Accessor(path));
-                    } else {
+                    }
+                    else {
                         loadInjectionMetadata(field.getType(), injectionMetadata, path);
                     }
                 }
@@ -146,7 +145,7 @@ public class MetadataLoader
                     String description = optionAnnotation.description();
 
                     int arity = optionAnnotation.arity();
-                    Preconditions.checkArgument(arity >= 0 || arity == Integer.MIN_VALUE, "Invalid arity for option %s", name);
+                    checkArgument(arity >= 0 || arity == Integer.MIN_VALUE, "Invalid arity for option %s", name);
 
                     if (optionAnnotation.arity() >= 0) {
                         arity = optionAnnotation.arity();
@@ -209,16 +208,11 @@ public class MetadataLoader
             metadataIndex.put(option, option);
         }
 
-        options = ImmutableList.copyOf(transform(metadataIndex.asMap().values(), new Function<Collection<OptionMetadata>, OptionMetadata>()
-        {
-            @Override
-            public OptionMetadata apply(@Nullable Collection<OptionMetadata> options)
-            {
-                return new OptionMetadata(options);
-            }
-        }));
+        options = metadataIndex.asMap().values().stream()
+                .map(OptionMetadata::new)
+                .collect(toImmutableList());
 
-        Map<String, OptionMetadata> optionIndex = newHashMap();
+        Map<String, OptionMetadata> optionIndex = new HashMap<>();
         for (OptionMetadata option : options) {
             for (String optionName : option.getOptions()) {
                 if (optionIndex.containsKey(optionName)) {
@@ -241,11 +235,11 @@ public class MetadataLoader
 
     private static class InjectionMetadata
     {
-        private List<OptionMetadata> globalOptions = newArrayList();
-        private List<OptionMetadata> groupOptions = newArrayList();
-        private List<OptionMetadata> commandOptions = newArrayList();
-        private List<ArgumentsMetadata> arguments = newArrayList();
-        private List<Accessor> metadataInjections = newArrayList();
+        private List<OptionMetadata> globalOptions = new ArrayList<>();
+        private List<OptionMetadata> groupOptions = new ArrayList<>();
+        private List<OptionMetadata> commandOptions = new ArrayList<>();
+        private List<ArgumentsMetadata> arguments = new ArrayList<>();
+        private List<Accessor> metadataInjections = new ArrayList<>();
 
         private void compact()
         {
diff --git a/src/main/java/io/airlift/airline/model/OptionMetadata.java b/src/main/java/io/airlift/airline/model/OptionMetadata.java
index 095e0fa..4144938 100644
--- a/src/main/java/io/airlift/airline/model/OptionMetadata.java
+++ b/src/main/java/io/airlift/airline/model/OptionMetadata.java
@@ -1,18 +1,16 @@
 package io.airlift.airline.model;
 
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import io.airlift.airline.Accessor;
 import io.airlift.airline.OptionType;
 
-import javax.annotation.Nullable;
 import java.lang.reflect.Field;
+import java.util.HashSet;
 import java.util.Set;
 
-import static com.google.common.collect.Sets.newHashSet;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
 
 public class OptionMetadata
 {
@@ -36,12 +34,12 @@ public class OptionMetadata
             Iterable<String> allowedValues,
             Iterable<Field> path)
     {
-        Preconditions.checkNotNull(optionType, "optionType is null");
-        Preconditions.checkNotNull(options, "options is null");
-        Preconditions.checkArgument(!Iterables.isEmpty(options), "options is empty");
-        Preconditions.checkNotNull(title, "title is null");
-        Preconditions.checkNotNull(path, "path is null");
-        Preconditions.checkArgument(!Iterables.isEmpty(path), "path is empty");
+        requireNonNull(optionType, "optionType is null");
+        requireNonNull(options, "options is null");
+        checkArgument(!Iterables.isEmpty(options), "options is empty");
+        requireNonNull(title, "title is null");
+        requireNonNull(path, "path is null");
+        checkArgument(!Iterables.isEmpty(path), "path is empty");
 
         this.optionType = optionType;
         this.options = ImmutableSet.copyOf(options);
@@ -63,8 +61,8 @@ public class OptionMetadata
 
     public OptionMetadata(Iterable<OptionMetadata> options)
     {
-        Preconditions.checkNotNull(options, "options is null");
-        Preconditions.checkArgument(!Iterables.isEmpty(options), "options is empty");
+        requireNonNull(options, "options is null");
+        checkArgument(!Iterables.isEmpty(options), "options is empty");
 
         OptionMetadata option = options.iterator().next();
 
@@ -82,9 +80,9 @@ public class OptionMetadata
             this.allowedValues = null;
         }
 
-        Set<Accessor> accessors = newHashSet();
+        Set<Accessor> accessors = new HashSet<>();
         for (OptionMetadata other : options) {
-            Preconditions.checkArgument(option.equals(other),
+            checkArgument(option.equals(other),
                     "Conflicting options definitions: %s, %s", option, other);
 
             accessors.addAll(other.getAccessors());
@@ -217,26 +215,4 @@ public class OptionMetadata
         sb.append('}');
         return sb.toString();
     }
-
-    public static Function<OptionMetadata, Set<String>> optionsGetter()
-    {
-        return new Function<OptionMetadata, Set<String>>()
-        {
-            public Set<String> apply(OptionMetadata input)
-            {
-                return input.getOptions();
-            }
-        };
-    }
-
-    public static Predicate<OptionMetadata> isHiddenPredicate()
-    {
-        return new Predicate<OptionMetadata>() {
-            @Override
-            public boolean apply(@Nullable OptionMetadata input)
-            {
-                return !input.isHidden();
-            }
-        };
-    }
 }
diff --git a/src/test/java/io/airlift/airline/ArgumentConversion.java b/src/test/java/io/airlift/airline/ArgumentConversion.java
new file mode 100644
index 0000000..c6a707f
--- /dev/null
+++ b/src/test/java/io/airlift/airline/ArgumentConversion.java
@@ -0,0 +1,108 @@
+package io.airlift.airline;
+
+class ArgumentConversion
+{
+    private ArgumentConversion() {}
+
+    public static void main(String... args)
+    {
+        Cli.CliBuilder<Runnable> builder = Cli.<Runnable>builder("argtest")
+                .withDescription("test the argument converter")
+                .withDefaultCommand(ArgumentConversions.class);
+
+        Cli<Runnable> parser = builder.build();
+        parser.parse(args).run();
+    }
+
+    @Command(name = "argumentconversion")
+    public static class ArgumentConversions
+            implements Runnable
+    {
+        @Option(type = OptionType.GLOBAL, name = "--constructor", description = "String of max. 5 chars")
+        public ArgumentConstructor constructedArg;
+
+        @Option(type = OptionType.GLOBAL, name = "--from-string", description = "String of max. 5 chars")
+        public ArgumentFromString fromStringArg;
+
+        @Option(type = OptionType.GLOBAL, name = "--value-of", description = "String of max. 5 chars")
+        public ArgumentValueOf valueOfArg;
+
+        @Override
+        public void run()
+        {
+            System.out.println("ConstructedArg: " + constructedArg);
+            System.out.println("FromStringArg: " + fromStringArg);
+            System.out.println("ValueOfArg: " + valueOfArg);
+        }
+    }
+
+    public static class ArgumentConstructor
+    {
+        private String value;
+
+        public ArgumentConstructor(String argument) throws IllegalArgumentException
+        {
+            if (argument.length() > 5) {
+                throw new IllegalArgumentException("(1) Argument too long.");
+            }
+
+            this.value = argument;
+        }
+
+        @Override
+        public String toString()
+        {
+            return value;
+        }
+    }
+
+    public static class ArgumentValueOf
+    {
+        private String value;
+
+        public static ArgumentValueOf valueOf(String str)
+        {
+            return new ArgumentValueOf(str);
+        }
+
+        private ArgumentValueOf(String argument) throws IllegalArgumentException
+        {
+            if (argument.length() > 5) {
+                throw new IllegalArgumentException("(2) Argument too long.");
+            }
+
+            this.value = argument;
+        }
+
+        @Override
+        public String toString()
+        {
+            return value;
+        }
+    }
+
+    public static class ArgumentFromString
+    {
+        private String value;
+
+        public static ArgumentFromString fromString(String str)
+        {
+            return new ArgumentFromString(str);
+        }
+
+        private ArgumentFromString(String argument) throws IllegalArgumentException
+        {
+            if (argument.length() > 5) {
+                throw new IllegalArgumentException("(3) Argument too long.");
+            }
+
+            this.value = argument;
+        }
+
+        @Override
+        public String toString()
+        {
+            return value;
+        }
+    }
+}
diff --git a/src/test/java/io/airlift/airline/Git.java b/src/test/java/io/airlift/airline/Git.java
index e20589b..25bcc14 100644
--- a/src/test/java/io/airlift/airline/Git.java
+++ b/src/test/java/io/airlift/airline/Git.java
@@ -6,8 +6,10 @@ import java.util.List;
 
 import static io.airlift.airline.OptionType.GLOBAL;
 
-public class Git
+public final class Git
 {
+    private Git() {}
+
     public static void main(String... args)
     {
         CliBuilder<Runnable> builder = Cli.<Runnable>builder("git")
diff --git a/src/test/java/io/airlift/airline/TestArgumentConversion.java b/src/test/java/io/airlift/airline/TestArgumentConversion.java
new file mode 100644
index 0000000..1143101
--- /dev/null
+++ b/src/test/java/io/airlift/airline/TestArgumentConversion.java
@@ -0,0 +1,65 @@
+package io.airlift.airline;
+
+import com.google.common.base.Joiner;
+import org.testng.annotations.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+public class TestArgumentConversion
+{
+    @Test
+    public void testConstuctorSuccessful()
+    {
+        ArgConverter("--constructor", "12345");
+    }
+
+    @Test
+    public void testConstuctorFailure()
+    {
+        assertThatThrownBy(() -> ArgConverter("--constructor", "123456"))
+                .isInstanceOf(ParseOptionConversionException.class)
+                .satisfies(e -> assertThat(e.getCause())
+                    .isInstanceOf(IllegalArgumentException.class)
+                    .hasMessage("(1) Argument too long."));
+    }
+
+    @Test
+    public void testValueOfSuccesful()
+    {
+        ArgConverter("--value-of", "12345");
+    }
+
+    @Test
+    public void testValueOfFailure()
+    {
+        assertThatThrownBy(() -> ArgConverter("--value-of", "123456"))
+                .isInstanceOf(ParseOptionConversionException.class)
+                .satisfies(e -> assertThat(e.getCause())
+                    .isInstanceOf(IllegalArgumentException.class)
+                    .hasMessage("(2) Argument too long."));
+    }
+
+    @Test
+    public void testFromStringSuccessful()
+    {
+        ArgConverter("--from-string", "12345");
+    }
+
+    @Test
+    public void testFromStringFailure()
+    {
+        assertThatThrownBy(() -> ArgConverter("--from-string", "123456"))
+                .isInstanceOf(ParseOptionConversionException.class)
+                .satisfies(e -> assertThat(e.getCause())
+                    .isInstanceOf(IllegalArgumentException.class)
+                    .hasMessage("(3) Argument too long."));
+    }
+
+    private void ArgConverter(String... args)
+    {
+        System.out.println("$ argumentconversion " + Joiner.on(' ').join(args));
+        ArgumentConversion.main(args);
+        System.out.println();
+    }
+}
diff --git a/src/test/java/io/airlift/airline/TestCli.java b/src/test/java/io/airlift/airline/TestCli.java
new file mode 100644
index 0000000..900e4b7
--- /dev/null
+++ b/src/test/java/io/airlift/airline/TestCli.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.airlift.airline;
+
+import io.airlift.airline.Cli.CliBuilder;
+import org.testng.annotations.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+public class TestCli
+{
+    @Test
+    public void testGroupWithoutDefaultCommand()
+    {
+        CliBuilder<Runnable> builder = Cli.builder("command");
+        builder.withGroup("subcommand")
+                .withCommand(Help.class);
+
+        Cli<Runnable> cli = builder.build();
+
+        assertThatThrownBy(cli::parse)
+                .isInstanceOf(ParseCommandMissingException.class)
+                .hasMessage("No command specified");
+
+        assertThatThrownBy(() -> cli.parse("subcommand"))
+                .isInstanceOf(ParseCommandMissingException.class)
+                .hasMessage("No command specified");
+
+        assertThat(cli.parse("subcommand", "help")).isInstanceOf(Help.class);
+    }
+}
diff --git a/src/test/java/io/airlift/airline/TestCommand.java b/src/test/java/io/airlift/airline/TestCommand.java
index 4e8bd77..ca22e97 100644
--- a/src/test/java/io/airlift/airline/TestCommand.java
+++ b/src/test/java/io/airlift/airline/TestCommand.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableList;
 import io.airlift.airline.Cli.CliBuilder;
 import io.airlift.airline.args.Args1;
 import io.airlift.airline.args.Args2;
+import io.airlift.airline.args.Args3;
 import io.airlift.airline.args.ArgsArityString;
 import io.airlift.airline.args.ArgsBooleanArity;
 import io.airlift.airline.args.ArgsBooleanArity0;
@@ -54,6 +55,31 @@ import static org.testng.Assert.assertTrue;
 
 public class TestCommand
 {
+    @Test
+    public void commandOptionWithoutValue()
+            throws ParseException
+    {
+        Args3 args = singleCommandParser(Args3.class).parse("Args3", "-noValue");
+        assertTrue(args.noValue);
+    }
+
+    @Test
+    public void commandOptionWithOneValue()
+            throws ParseException
+    {
+        Args3 args = singleCommandParser(Args3.class).parse("Args3", "-oneValue", "1");
+        assertEquals(args.oneValue, 1);
+    }
+
+    @Test
+    public void commandOptionWithMultipleValues()
+            throws ParseException
+    {
+        Args3 args = singleCommandParser(Args3.class).parse("Args3", "-twoValues", "1", "2");
+        assertEquals(args.twoValues.get(0), Integer.valueOf(1));
+        assertEquals(args.twoValues.get(1), Integer.valueOf(2));
+    }
+
     @Test
     public void simpleArgs()
             throws ParseException
@@ -128,7 +154,7 @@ public class TestCommand
     public void repeatedArgs()
     {
         Cli<Args1> parser = singleCommandParser(Args1.class);
-        CommandMetadata command = find(parser.getMetadata().getDefaultGroupCommands(), compose(equalTo("Args1"), CommandMetadata.nameGetter()));
+        CommandMetadata command = find(parser.getMetadata().getDefaultGroupCommands(), compose(equalTo("Args1"), CommandMetadata::getName));
         assertEquals(command.getAllOptions().size(), 8);
     }
 
@@ -399,6 +425,7 @@ public class TestCommand
             @Option(name = "-long")
             public long l;
         }
+
         singleCommandParser(A.class).parse("-lon", "32");
     }
 }
diff --git a/src/test/java/io/airlift/airline/TestGalaxyCommandLineParser.java b/src/test/java/io/airlift/airline/TestGalaxyCommandLineParser.java
index 499c182..2d958c4 100644
--- a/src/test/java/io/airlift/airline/TestGalaxyCommandLineParser.java
+++ b/src/test/java/io/airlift/airline/TestGalaxyCommandLineParser.java
@@ -1,17 +1,16 @@
 package io.airlift.airline;
 
 import com.google.common.base.Joiner;
-import com.google.common.collect.Lists;
 import io.airlift.airline.Cli.CliBuilder;
 import org.testng.annotations.Test;
 
 import javax.inject.Inject;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import static com.google.common.base.MoreObjects.firstNonNull;
 import static com.google.common.base.MoreObjects.toStringHelper;
-import static com.google.common.collect.Lists.newArrayList;
 import static io.airlift.airline.OptionType.GLOBAL;
 
 public class TestGalaxyCommandLineParser
@@ -89,7 +88,7 @@ public class TestGalaxyCommandLineParser
     public static class GlobalOptions
     {
         @Option(type = GLOBAL, name = "--debug", description = "Enable debug messages")
-        public boolean debug = false;
+        public boolean debug;
 
         @Option(type = GLOBAL, name = "--coordinator", description = "Galaxy coordinator host (overrides GALAXY_COORDINATOR)")
         public String coordinator = firstNonNull(System.getenv("GALAXY_COORDINATOR"), "http://localhost:64000");
@@ -141,16 +140,16 @@ public class TestGalaxyCommandLineParser
     public static class AgentFilter
     {
         @Option(name = {"-i", "--host"}, description = "Select slots on the given host")
-        public final List<String> host = newArrayList();
+        public final List<String> host = new ArrayList<>();
 
         @Option(name = {"-I", "--ip"}, description = "Select slots at the given IP address")
-        public final List<String> ip = newArrayList();
+        public final List<String> ip = new ArrayList<>();
 
         @Option(name = {"-u", "--uuid"}, description = "Select slot with the given UUID")
-        public final List<String> uuid = newArrayList();
+        public final List<String> uuid = new ArrayList<>();
 
         @Option(name = {"-s", "--state"}, description = "Select 'r{unning}', 's{topped}' or 'unknown' slots")
-        public final List<String> state = newArrayList();
+        public final List<String> state = new ArrayList<>();
 
         @Override
         public String toString()
@@ -164,7 +163,7 @@ public class TestGalaxyCommandLineParser
         }
     }
 
-    public static abstract class GalaxyCommand
+    public abstract static class GalaxyCommand
     {
         @Inject
         public GlobalOptions globalOptions = new GlobalOptions();
@@ -210,7 +209,7 @@ public class TestGalaxyCommandLineParser
     public static class InstallCommand
             extends GalaxyCommand
     {
-        @Option(name = {"--count"}, description = "Number of instances to install")
+        @Option(name = "--count", description = "Number of instances to install")
         public int count = 1;
 
         @Inject
@@ -218,7 +217,7 @@ public class TestGalaxyCommandLineParser
 
         @Arguments(usage = "<groupId:artifactId[:packaging[:classifier]]:version> @<component:pools:version>",
                 description = "The binary and @configuration to install.  The default packaging is tar.gz")
-        public final List<String> assignment = Lists.newArrayList();
+        public final List<String> assignment = new ArrayList<>();
 
         @Override
         public String toString()
@@ -241,7 +240,7 @@ public class TestGalaxyCommandLineParser
 
         @Arguments(usage = "[<binary-version>] [@<config-version>]",
                 description = "Version of the binary and/or @configuration")
-        public final List<String> versions = Lists.newArrayList();
+        public final List<String> versions = new ArrayList<>();
 
         @Override
         public String toString()
@@ -363,10 +362,10 @@ public class TestGalaxyCommandLineParser
     public static class AgentAddCommand
             extends GalaxyCommand
     {
-        @Option(name = {"--count"}, description = "Number of agents to provision")
+        @Option(name = "--count", description = "Number of agents to provision")
         public int count = 1;
 
-        @Option(name = {"--availability-zone"}, description = "Availability zone to provision")
+        @Option(name = "--availability-zone", description = "Availability zone to provision")
         public String availabilityZone;
 
         @Arguments(usage = "[<instance-type>]", description = "Instance type to provision")
diff --git a/src/test/java/io/airlift/airline/TestParametersDelegate.java b/src/test/java/io/airlift/airline/TestParametersDelegate.java
index 57b40de..7e49ec5 100644
--- a/src/test/java/io/airlift/airline/TestParametersDelegate.java
+++ b/src/test/java/io/airlift/airline/TestParametersDelegate.java
@@ -5,6 +5,7 @@ import org.testng.annotations.Test;
 
 import javax.inject.Inject;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import static com.google.common.collect.Lists.newArrayList;
@@ -72,7 +73,6 @@ public class TestParametersDelegate
     @Test
     public void delegatingSetsFieldsOnBothMainParamsAndTheDelegatedParams()
     {
-
         DelegatingSetsFieldsOnBothMainParamsAndTheDelegatedParams p = singleCommandParser(DelegatingSetsFieldsOnBothMainParamsAndTheDelegatedParams.class)
                 .parse("command", "-c", "--long-d", "123", "--long-b", "bValue");
         assertFalse(p.isA);
@@ -128,7 +128,7 @@ public class TestParametersDelegate
     {
         CombinedAndNestedDelegates p = singleCommandParser(CombinedAndNestedDelegates.class)
                 .parse("command", "-d", "234", "--list", "a", "--list", "b", "-a");
-        assertEquals(p.nestedDelegate2.nestedDelegate1.leafDelegate.list, newArrayList("value1", "value2", "a", "b"));
+        assertEquals(p.nestedDelegate2.nestedDelegate1.leafDelegate.list, ImmutableList.of("value1", "value2", "a", "b"));
         assertFalse(p.nestedDelegate2.nestedDelegate1.leafDelegate.bool);
         assertEquals(p.nestedDelegate2.nestedDelegate1.d, Integer.valueOf(234));
         assertFalse(p.nestedDelegate2.isC);
@@ -176,7 +176,6 @@ public class TestParametersDelegate
     @Test
     public void nullDelegatesAreAllowed()
     {
-
         NullDelegatesAreProhibited value = singleCommandParser(NullDelegatesAreProhibited.class).parse("command", "-a");
         assertEquals(value.delegate.a, true);
     }
@@ -214,13 +213,13 @@ public class TestParametersDelegate
         public static class Delegate1
         {
             @Arguments
-            public List<String> mainParams1 = newArrayList();
+            public List<String> mainParams1 = new ArrayList<>();
         }
 
         public static class Delegate2
         {
             @Arguments
-            public List<String> mainParams1 = newArrayList();
+            public List<String> mainParams1 = new ArrayList<>();
         }
 
         @Inject
@@ -247,13 +246,13 @@ public class TestParametersDelegate
         public static class Delegate1
         {
             @Arguments(description = "foo")
-            public List<String> mainParams1 = newArrayList();
+            public List<String> mainParams1 = new ArrayList<>();
         }
 
         public static class Delegate2
         {
             @Arguments(description = "bar")
-            public List<String> mainParams1 = newArrayList();
+            public List<String> mainParams1 = new ArrayList<>();
         }
 
         @Inject
diff --git a/src/test/java/io/airlift/airline/TestSingleCommand.java b/src/test/java/io/airlift/airline/TestSingleCommand.java
index ee1eeaf..5fa5781 100644
--- a/src/test/java/io/airlift/airline/TestSingleCommand.java
+++ b/src/test/java/io/airlift/airline/TestSingleCommand.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -130,7 +130,7 @@ public class TestSingleCommand
     public void repeatedArgs()
     {
         SingleCommand<Args1> parser = singleCommand(Args1.class);
-        CommandMetadata command = find(ImmutableList.of(parser.getCommandMetadata()), compose(equalTo("Args1"), CommandMetadata.nameGetter()));
+        CommandMetadata command = find(ImmutableList.of(parser.getCommandMetadata()), compose(equalTo("Args1"), CommandMetadata::getName));
         assertEquals(command.getAllOptions().size(), 8);
     }
 
@@ -379,6 +379,7 @@ public class TestSingleCommand
             @Option(name = "-long")
             public long l;
         }
+
         singleCommand(A.class).parse("32");
     }
 
diff --git a/src/test/java/io/airlift/airline/TestTypeConverter.java b/src/test/java/io/airlift/airline/TestTypeConverter.java
new file mode 100644
index 0000000..6376a9d
--- /dev/null
+++ b/src/test/java/io/airlift/airline/TestTypeConverter.java
@@ -0,0 +1,409 @@
+package io.airlift.airline;
+
+import com.google.common.primitives.Primitives;
+import org.testng.annotations.Test;
+
+import java.util.Date;
+import java.util.UUID;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class TestTypeConverter
+{
+    private TypeConverter tc = new TypeConverter();
+
+    @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "name is null")
+    public void nullNameShouldThrowException()
+    {
+        tc.convert(null, Boolean.class, "true");
+    }
+
+    @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "type is null")
+    public void nullTypeShouldThrowException()
+    {
+        valueTest(null, "true");
+    }
+
+    @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "value is null")
+    public void nullValueShouldThrowException()
+    {
+        valueTest(Byte.class, null);
+    }
+
+    @Test
+    public void stringNominal()
+    {
+        valueTest(String.class, "test");
+    }
+
+    @Test
+    public void stringCorner()
+    {
+        valueTest(String.class, "");
+    }
+
+    @Test
+    public void booleanNominalTrue()
+    {
+        valueTest(Boolean.class, "true");
+    }
+
+    @Test
+    public void booleanNominalFalse()
+    {
+        valueTest(boolean.class, "false");
+    }
+
+    @Test
+    public void booleanIncompatible()
+    {
+        Object obj = tc.convert("name", Boolean.class, "abc123!#%");
+        assertTrue(obj instanceof Boolean);
+        assertEquals((boolean) obj, false);
+    }
+
+    @Test
+    public void byteNominalTest()
+    {
+        valueTest(Byte.class, "100");
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"-129\" to a byte")
+    public void byteBoundaryMinMinus1()
+    {
+        valueTest(byte.class, "-129");
+    }
+
+    @Test
+    public void byteBoundaryMin()
+    {
+        valueTest(Byte.class, "-128");
+    }
+
+    @Test
+    public void byteBoundaryMinPlus1()
+    {
+        valueTest(byte.class, "-127");
+    }
+
+    @Test
+    public void byteBoundaryMaxMinus1()
+    {
+        valueTest(Byte.class, "126");
+    }
+
+    @Test
+    public void byteBoundaryMax()
+    {
+        valueTest(byte.class, "127");
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"128\" to a Byte")
+    public void byteBoundaryMaxPlus1()
+    {
+        valueTest(Byte.class, "128");
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"abc123!#%\" to a byte")
+    public void byteIncompatible()
+    {
+        valueTest(byte.class, "abc123!#%");
+    }
+
+    @Test
+    public void shortNominalTest()
+    {
+        valueTest(Short.class, "100");
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"-32769\" to a short")
+    public void shortBoundaryMinMinus1()
+    {
+        valueTest(short.class, "-32769");
+    }
+
+    @Test
+    public void shortBoundaryMin()
+    {
+        valueTest(Short.class, "-32768");
+    }
+
+    @Test
+    public void shortBoundaryMinPlus1()
+    {
+        valueTest(short.class, "-32767");
+    }
+
+    @Test
+    public void shortBoundaryMaxMinus1()
+    {
+        valueTest(Short.class, "32766");
+    }
+
+    @Test
+    public void shortBoundaryMax()
+    {
+        valueTest(short.class, "32767");
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"32768\" to a Short")
+    public void shortBoundaryMaxPlus1()
+    {
+        valueTest(Short.class, "32768");
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"abc123!#%\" to a short")
+    public void shortIncompatible()
+    {
+        valueTest(short.class, "abc123!#%");
+    }
+
+    @Test
+    public void intNominalTest()
+    {
+        valueTest(Integer.class, "100");
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"-2147483649\" to a int")
+    public void intBoundaryMinMinus1()
+    {
+        valueTest(int.class, "-2147483649");
+    }
+
+    @Test
+    public void intBoundaryMin()
+    {
+        valueTest(Integer.class, "-2147483648");
+    }
+
+    @Test
+    public void intBoundaryMinPlus1()
+    {
+        valueTest(int.class, "-2147483647");
+    }
+
+    @Test
+    public void intBoundaryMaxMinus1()
+    {
+        valueTest(Integer.class, "2147483646");
+    }
+
+    @Test
+    public void intBoundaryMax()
+    {
+        valueTest(int.class, "2147483647");
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"2147483648\" to a Integer")
+    public void intBoundaryMaxPlus1()
+    {
+        valueTest(Integer.class, "2147483648");
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"abc123!#%\" to a int")
+    public void intIncompatible()
+    {
+        valueTest(int.class, "abc123!#%");
+    }
+
+    @Test
+    public void longNominalTest()
+    {
+        valueTest(Long.class, "100");
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"-9223372036854775809\" to a long")
+    public void longBoundaryMinMinus1()
+    {
+        valueTest(long.class, "-9223372036854775809");
+    }
+
+    @Test
+    public void longBoundaryMin()
+    {
+        valueTest(Long.class, "-9223372036854775808");
+    }
+
+    @Test
+    public void longBoundaryMinPlus1()
+    {
+        valueTest(long.class, "-9223372036854775807");
+    }
+
+    @Test
+    public void longBoundaryMaxMinus1()
+    {
+        valueTest(Long.class, "9223372036854775806");
+    }
+
+    @Test
+    public void longBoundaryMax()
+    {
+        valueTest(long.class, "9223372036854775807");
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"9223372036854775808\" to a Long")
+    public void longBoundaryMaxPlus1()
+    {
+        valueTest(Long.class, "9223372036854775808");
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"abc123!#%\" to a long")
+    public void longIncompatible()
+    {
+        valueTest(long.class, "abc123!#%");
+    }
+
+    @Test
+    public void floatNominalTest()
+    {
+        valueTest(Float.class, "3.141");
+    }
+
+    @Test
+    public void floatBoundaryMinMinus1()
+    {
+        Object convertedType = tc.convert("name", float.class, "-1.4E-46");
+        assertTrue(convertedType instanceof Float);
+        assertEquals(String.valueOf(convertedType), "-0.0");
+    }
+
+    @Test
+    public void floatBoundaryMin()
+    {
+        valueTest(Float.class, "-1.4E-45");
+    }
+
+    @Test
+    public void floatBoundaryMinPlus1()
+    {
+        valueTest(float.class, "-1.4E-44");
+    }
+
+    @Test
+    public void floatBoundaryMaxMinus1()
+    {
+        valueTest(Float.class, "3.4E37");
+    }
+
+    @Test
+    public void floatBoundaryMax()
+    {
+        valueTest(float.class, "3.4E38");
+    }
+
+    @Test
+    public void floatBoundaryMaxPlus1()
+    {
+        Object convertedType = tc.convert("name", Float.class, "3.4E39");
+        assertTrue(convertedType instanceof Float);
+        assertEquals(String.valueOf(convertedType), "Infinity");
+    }
+
+    @Test
+    public void floatCorner()
+    {
+        Object convertedType = tc.convert("name", float.class, "100");
+        assertTrue(convertedType instanceof Float);
+        assertEquals(String.valueOf(convertedType), "100" + ".0");
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"abc123!#%\" to a Float")
+    public void floatIncompatible()
+    {
+        valueTest(Float.class, "abc123!#%");
+    }
+
+    @Test
+    public void doubleNominalTest()
+    {
+        valueTest(Double.class, "3.141");
+    }
+
+    @Test
+    public void doubleBoundaryMinMinus1()
+    {
+        Object convertedType = tc.convert("name", double.class, "4.9E-325");
+        assertTrue(convertedType instanceof Double);
+        assertEquals(String.valueOf(convertedType), "0.0");
+    }
+
+    @Test
+    public void doubleBoundaryMin()
+    {
+        valueTest(Double.class, "4.9E-324");
+    }
+
+    @Test
+    public void doubleBoundaryMinPlus1()
+    {
+        valueTest(double.class, "4.9E-323");
+    }
+
+    @Test
+    public void doubleBoundaryMaxMinus1()
+    {
+        valueTest(Double.class, "1.7976931348623158E307");
+    }
+
+    @Test
+    public void doubleBoundaryMax()
+    {
+        valueTest(double.class, "1.7976931348623157E308");
+    }
+
+    @Test
+    public void doubleBoundaryMaxPlus1()
+    {
+        Object convertedType = tc.convert("name", Double.class, "1.7976931348623157E309");
+        assertTrue(convertedType instanceof Double);
+        assertEquals(String.valueOf(convertedType), "Infinity");
+    }
+
+    @Test
+    public void doubleCorner()
+    {
+        Object convertedType = tc.convert("name", double.class, "100");
+        assertTrue(convertedType instanceof Double);
+        assertEquals(String.valueOf(convertedType), "100" + ".0");
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"abc123!#%\" to a double")
+    public void doubleIncompatible()
+    {
+        valueTest(double.class, "abc123!#%");
+    }
+
+    @Test
+    public void fromStringNominalTest()
+    {
+        valueTest(UUID.class, UUID.randomUUID().toString());
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"abc123!#%\" to a UUID")
+    public void fromStringIncompatible()
+    {
+        valueTest(UUID.class, "abc123!#%");
+    }
+
+    @Test
+    public void valueOfNominalTest()
+    {
+        valueTest(Date.class, new Date().toString());
+    }
+
+    @Test(expectedExceptions = ParseOptionConversionException.class, expectedExceptionsMessageRegExp = "name: can not convert \"abc123!#%\" to a Date")
+    public void valueOfIncompatible()
+    {
+        valueTest(Date.class, "abc123!#%");
+    }
+
+    private void valueTest(Class<?> type, String testValue)
+    {
+        Object convertedType = tc.convert("name", type, testValue);
+        Class<?> expectedClass = Primitives.wrap(type);
+        assertEquals(convertedType.getClass(), expectedClass);
+        assertEquals(String.valueOf(convertedType), testValue);
+    }
+}
diff --git a/src/test/java/io/airlift/airline/TestingUtil.java b/src/test/java/io/airlift/airline/TestingUtil.java
index 20107d6..3877b18 100644
--- a/src/test/java/io/airlift/airline/TestingUtil.java
+++ b/src/test/java/io/airlift/airline/TestingUtil.java
@@ -1,7 +1,9 @@
 package io.airlift.airline;
 
-public class TestingUtil
+public final class TestingUtil
 {
+    private TestingUtil() {}
+
     public static <T> Cli<T> singleCommandParser(Class<T> commandClass)
     {
         return Cli.<T>builder("parser")
diff --git a/src/test/java/io/airlift/airline/args/Args1.java b/src/test/java/io/airlift/airline/args/Args1.java
index 779e223..ebc52b8 100644
--- a/src/test/java/io/airlift/airline/args/Args1.java
+++ b/src/test/java/io/airlift/airline/args/Args1.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -18,12 +18,12 @@
 
 package io.airlift.airline.args;
 
-import com.google.common.collect.Lists;
 import io.airlift.airline.Arguments;
 import io.airlift.airline.Command;
 import io.airlift.airline.Option;
 
 import java.math.BigDecimal;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
@@ -31,7 +31,7 @@ import java.util.List;
 public class Args1
 {
     @Arguments
-    public List<String> parameters = Lists.newArrayList();
+    public List<String> parameters = new ArrayList<>();
 
     @Option(name = {"-log", "-verbose"}, description = "Level of verbosity")
     public Integer verbose = 1;
@@ -40,7 +40,7 @@ public class Args1
     public String groups;
 
     @Option(name = "-debug", description = "Debug mode")
-    public boolean debug = false;
+    public boolean debug;
 
     @Option(name = "-long", description = "A long number")
     public long l;
diff --git a/src/test/java/io/airlift/airline/args/Args2.java b/src/test/java/io/airlift/airline/args/Args2.java
index bb6fe54..75478f6 100644
--- a/src/test/java/io/airlift/airline/args/Args2.java
+++ b/src/test/java/io/airlift/airline/args/Args2.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -22,15 +22,14 @@ import io.airlift.airline.Arguments;
 import io.airlift.airline.Command;
 import io.airlift.airline.Option;
 
+import java.util.ArrayList;
 import java.util.List;
 
-import static com.google.common.collect.Lists.newArrayList;
-
 @Command(name = "Args2")
 public class Args2
 {
     @Arguments(description = "List of parameters")
-    public List<String> parameters = com.google.common.collect.Lists.newArrayList();
+    public List<String> parameters = new ArrayList<>();
 
     @Option(name = {"-log", "-verbose"}, description = "Level of verbosity")
     public Integer verbose = 1;
@@ -39,8 +38,8 @@ public class Args2
     public String groups;
 
     @Option(name = "-debug", description = "Debug mode")
-    public boolean debug = false;
+    public boolean debug;
 
     @Option(name = "-host", description = "The host")
-    public List<String> hosts = newArrayList();
+    public List<String> hosts = new ArrayList<>();
 }
diff --git a/src/test/java/io/airlift/airline/args/Args3.java b/src/test/java/io/airlift/airline/args/Args3.java
new file mode 100644
index 0000000..ce58ad6
--- /dev/null
+++ b/src/test/java/io/airlift/airline/args/Args3.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.airlift.airline.args;
+
+import io.airlift.airline.Command;
+import io.airlift.airline.Option;
+
+import java.util.List;
+
+@Command(name = "Args3", description = "args3 description")
+public class Args3
+{
+    @Option(name = "-noValue", description = "0 values")
+    public boolean noValue;
+
+    @Option(name = "-oneValue", description = "1 value")
+    public int oneValue;
+
+    @Option(name = "-twoValues", description = "2 values", arity = 2)
+    public List<Integer> twoValues;
+}
diff --git a/src/test/java/io/airlift/airline/args/ArgsArityString.java b/src/test/java/io/airlift/airline/args/ArgsArityString.java
index f17e4c2..26e219d 100644
--- a/src/test/java/io/airlift/airline/args/ArgsArityString.java
+++ b/src/test/java/io/airlift/airline/args/ArgsArityString.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -32,7 +32,6 @@ import java.util.List;
 @Command(name = "ArgsArityString")
 public class ArgsArityString
 {
-
     @Option(name = "-pairs", arity = 2, description = "Pairs")
     public List<String> pairs;
 
diff --git a/src/test/java/io/airlift/airline/args/ArgsBooleanArity.java b/src/test/java/io/airlift/airline/args/ArgsBooleanArity.java
index 91070d8..a2a5291 100644
--- a/src/test/java/io/airlift/airline/args/ArgsBooleanArity.java
+++ b/src/test/java/io/airlift/airline/args/ArgsBooleanArity.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
diff --git a/src/test/java/io/airlift/airline/args/ArgsBooleanArity0.java b/src/test/java/io/airlift/airline/args/ArgsBooleanArity0.java
index cb19928..ec77d09 100644
--- a/src/test/java/io/airlift/airline/args/ArgsBooleanArity0.java
+++ b/src/test/java/io/airlift/airline/args/ArgsBooleanArity0.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
diff --git a/src/test/java/io/airlift/airline/args/ArgsDefault.java b/src/test/java/io/airlift/airline/args/ArgsDefault.java
index d1f758f..f701dfd 100644
--- a/src/test/java/io/airlift/airline/args/ArgsDefault.java
+++ b/src/test/java/io/airlift/airline/args/ArgsDefault.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -18,16 +18,16 @@
 
 package io.airlift.airline.args;
 
-import com.google.common.collect.Lists;
 import io.airlift.airline.Arguments;
 import io.airlift.airline.Option;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class ArgsDefault
 {
     @Arguments
-    public List<String> parameters = Lists.newArrayList();
+    public List<String> parameters = new ArrayList<>();
 
     @Option(name = "-log", description = "Level of verbosity")
     public Integer log = 1;
@@ -36,7 +36,7 @@ public class ArgsDefault
     public String groups;
 
     @Option(name = "-debug", description = "Debug mode")
-    public boolean debug = false;
+    public boolean debug;
 
     @Option(name = "-level", description = "A long number")
     public long level;
diff --git a/src/test/java/io/airlift/airline/args/ArgsEnum.java b/src/test/java/io/airlift/airline/args/ArgsEnum.java
index 75fc99c..a88e212 100644
--- a/src/test/java/io/airlift/airline/args/ArgsEnum.java
+++ b/src/test/java/io/airlift/airline/args/ArgsEnum.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -29,7 +29,6 @@ import io.airlift.airline.Option;
 @Command(name = "ArgsEnum")
 public class ArgsEnum
 {
-
     public enum ChoiceType
     {
         ONE, TWO, THREE
@@ -38,5 +37,3 @@ public class ArgsEnum
     @Option(name = "-choice", description = "Choice parameter")
     public ChoiceType choice = ChoiceType.ONE;
 }
-
-
diff --git a/src/test/java/io/airlift/airline/args/ArgsInherited.java b/src/test/java/io/airlift/airline/args/ArgsInherited.java
index 59d1d79..3c86ae2 100644
--- a/src/test/java/io/airlift/airline/args/ArgsInherited.java
+++ b/src/test/java/io/airlift/airline/args/ArgsInherited.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
diff --git a/src/test/java/io/airlift/airline/args/ArgsMultipleUnparsed.java b/src/test/java/io/airlift/airline/args/ArgsMultipleUnparsed.java
index 042daa0..634ea08 100644
--- a/src/test/java/io/airlift/airline/args/ArgsMultipleUnparsed.java
+++ b/src/test/java/io/airlift/airline/args/ArgsMultipleUnparsed.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
diff --git a/src/test/java/io/airlift/airline/args/ArgsPrivate.java b/src/test/java/io/airlift/airline/args/ArgsPrivate.java
index be54a8f..37f0ba2 100644
--- a/src/test/java/io/airlift/airline/args/ArgsPrivate.java
+++ b/src/test/java/io/airlift/airline/args/ArgsPrivate.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
diff --git a/src/test/java/io/airlift/airline/args/ArgsRequired.java b/src/test/java/io/airlift/airline/args/ArgsRequired.java
index 05a4982..e7d64e0 100644
--- a/src/test/java/io/airlift/airline/args/ArgsRequired.java
+++ b/src/test/java/io/airlift/airline/args/ArgsRequired.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -21,11 +21,12 @@ package io.airlift.airline.args;
 import io.airlift.airline.Arguments;
 import io.airlift.airline.Command;
 
+import java.util.ArrayList;
 import java.util.List;
 
 @Command(name = "ArgsRequired")
 public class ArgsRequired
 {
     @Arguments(description = "List of files", required = true)
-    public List<String> parameters = com.google.common.collect.Lists.newArrayList();
+    public List<String> parameters = new ArrayList<>();
 }
diff --git a/src/test/java/io/airlift/airline/args/ArgsSingleChar.java b/src/test/java/io/airlift/airline/args/ArgsSingleChar.java
index 2eb18de..39ca0a9 100644
--- a/src/test/java/io/airlift/airline/args/ArgsSingleChar.java
+++ b/src/test/java/io/airlift/airline/args/ArgsSingleChar.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -18,45 +18,45 @@
 
 package io.airlift.airline.args;
 
-import com.google.common.collect.Lists;
 import io.airlift.airline.Arguments;
 import io.airlift.airline.Command;
 import io.airlift.airline.Option;
 
+import java.util.ArrayList;
 import java.util.List;
 
 @Command(name = "ArgsSingleChar")
 public class ArgsSingleChar
 {
     @Arguments
-    public List<String> parameters = Lists.newArrayList();
+    public List<String> parameters = new ArrayList<>();
 
-    @Option(name = {"-l"}, description = "Long")
-    public boolean l = false;
+    @Option(name = "-l", description = "Long")
+    public boolean l;
 
     @Option(name = "-g", description = "Global")
-    public boolean g = false;
+    public boolean g;
 
     @Option(name = "-d", description = "Debug mode")
-    public boolean d = false;
+    public boolean d;
 
     @Option(name = "-s", description = "A string")
-    public String s = null;
+    public String s;
 
     @Option(name = "-p", description = "A path")
-    public String p = null;
+    public String p;
 
     @Option(name = "-n", description = "No action")
-    public boolean n = false;
+    public boolean n;
 
     @Option(name = "-2", description = "Two")
-    public boolean two = false;
+    public boolean two;
 
     @Option(name = "-f", description = "A filename")
-    public String f = null;
+    public String f;
 
     @Option(name = "-z", description = "Compress")
-    public boolean z = false;
+    public boolean z;
 
     @Option(name = "--D", description = "Directory")
     public String dir;
diff --git a/src/test/java/io/airlift/airline/args/CommandHidden.java b/src/test/java/io/airlift/airline/args/CommandHidden.java
index 6f7c71d..f73315a 100644
--- a/src/test/java/io/airlift/airline/args/CommandHidden.java
+++ b/src/test/java/io/airlift/airline/args/CommandHidden.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
diff --git a/src/test/java/io/airlift/airline/args/CommandLineArgs.java b/src/test/java/io/airlift/airline/args/CommandLineArgs.java
index b8b91de..97bab66 100644
--- a/src/test/java/io/airlift/airline/args/CommandLineArgs.java
+++ b/src/test/java/io/airlift/airline/args/CommandLineArgs.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
@@ -22,14 +22,14 @@ import io.airlift.airline.Arguments;
 import io.airlift.airline.Command;
 import io.airlift.airline.Option;
 
+import java.util.ArrayList;
 import java.util.List;
 
 @Command(name = "CommandLineArgs")
 public class CommandLineArgs
 {
-
     @Arguments(description = "The XML suite files to run")
-    public List<String> suiteFiles = com.google.common.collect.Lists.newArrayList();
+    public List<String> suiteFiles = new ArrayList<>();
 
     @Option(name = {"-log", "-verbose"}, description = "Level of verbosity")
     public Integer verbose;
diff --git a/src/test/java/io/airlift/airline/args/OptionsHidden.java b/src/test/java/io/airlift/airline/args/OptionsHidden.java
index ac1e6e4..c46c738 100644
--- a/src/test/java/io/airlift/airline/args/OptionsHidden.java
+++ b/src/test/java/io/airlift/airline/args/OptionsHidden.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
diff --git a/src/test/java/io/airlift/airline/args/OptionsRequired.java b/src/test/java/io/airlift/airline/args/OptionsRequired.java
index 30fdd9a..e15984d 100644
--- a/src/test/java/io/airlift/airline/args/OptionsRequired.java
+++ b/src/test/java/io/airlift/airline/args/OptionsRequired.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
diff --git a/src/test/java/io/airlift/airline/command/CommandAdd.java b/src/test/java/io/airlift/airline/command/CommandAdd.java
index d0b07f9..17ffbaa 100644
--- a/src/test/java/io/airlift/airline/command/CommandAdd.java
+++ b/src/test/java/io/airlift/airline/command/CommandAdd.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
diff --git a/src/test/java/io/airlift/airline/command/CommandCommit.java b/src/test/java/io/airlift/airline/command/CommandCommit.java
index dd797a5..73bf04f 100644
--- a/src/test/java/io/airlift/airline/command/CommandCommit.java
+++ b/src/test/java/io/airlift/airline/command/CommandCommit.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
diff --git a/src/test/java/io/airlift/airline/command/CommandMain.java b/src/test/java/io/airlift/airline/command/CommandMain.java
index 6da9fe9..a1d896e 100644
--- a/src/test/java/io/airlift/airline/command/CommandMain.java
+++ b/src/test/java/io/airlift/airline/command/CommandMain.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.
diff --git a/src/test/java/io/airlift/airline/command/CommandTest.java b/src/test/java/io/airlift/airline/command/CommandTest.java
index c4d89f1..d1f1f6f 100644
--- a/src/test/java/io/airlift/airline/command/CommandTest.java
+++ b/src/test/java/io/airlift/airline/command/CommandTest.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2010 the original author or authors.
  * See the notice.md file distributed with this work for additional
  * information regarding copyright ownership.

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/share/maven-repo/io/airlift/airline/0.10-SNAPSHOT/airline-0.10-SNAPSHOT.pom
lrwxrwxrwx  root/root   /usr/share/java/airline-0.10-SNAPSHOT.jar -> airline.jar
lrwxrwxrwx  root/root   /usr/share/maven-repo/io/airlift/airline/0.10-SNAPSHOT/airline-0.10-SNAPSHOT.jar -> ../../../../../java/airline.jar

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/share/maven-repo/io/airlift/airline/0.7/airline-0.7.pom
lrwxrwxrwx  root/root   /usr/share/java/airline-0.7.jar -> airline.jar
lrwxrwxrwx  root/root   /usr/share/maven-repo/io/airlift/airline/0.7/airline-0.7.jar -> ../../../../../java/airline.jar

Control files: lines which differ (wdiff format)

  • Depends: libatinject-jsr330-api-java, libfindbugs-annotations-java, libguava-java libguava-java, libjsr305-java

More details

Full run details