diff --git a/pom.xml b/pom.xml
index 9d56f8c7..35f683f3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -39,6 +39,12 @@
spring-shell
1.2.0.BUILD-SNAPSHOT
+
+ com.beust
+ jcommander
+ 1.48
+ true
+
diff --git a/src/main/java/org/springframework/shell2/jcommander/JCommanderParameterResolver.java b/src/main/java/org/springframework/shell2/jcommander/JCommanderParameterResolver.java
new file mode 100644
index 00000000..a6105ed6
--- /dev/null
+++ b/src/main/java/org/springframework/shell2/jcommander/JCommanderParameterResolver.java
@@ -0,0 +1,63 @@
+package org.springframework.shell2.jcommander;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.beust.jcommander.DynamicParameter;
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.ParametersDelegate;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.core.MethodParameter;
+import org.springframework.shell2.ParameterResolver;
+import org.springframework.util.ReflectionUtils;
+
+/**
+ * Created by ericbottard on 15/12/15.
+ */
+public class JCommanderParameterResolver implements ParameterResolver {
+
+ private static final Collection> JCOMMANDER_ANNOTATIONS =
+ Arrays.asList(Parameter.class, DynamicParameter.class, ParametersDelegate.class);
+
+ @Override
+ public boolean supports(MethodParameter parameter) {
+ AtomicBoolean isSupported = new AtomicBoolean(false);
+
+ Class> parameterType = parameter.getParameterType();
+ ReflectionUtils.doWithFields(parameterType, field -> {
+ ReflectionUtils.makeAccessible(field);
+ boolean hasAnnotation = Arrays.asList(field.getAnnotations())
+ .stream()
+ .map(Annotation::annotationType)
+ .anyMatch(JCOMMANDER_ANNOTATIONS::contains);
+ isSupported.compareAndSet(false, hasAnnotation);
+
+ });
+
+ ReflectionUtils.doWithMethods(parameterType, method -> {
+ ReflectionUtils.makeAccessible(method);
+ boolean hasAnnotation = Arrays.asList(method.getAnnotations())
+ .stream()
+ .map(Annotation::annotationType)
+ .anyMatch(Parameter.class::equals);
+ isSupported.compareAndSet(false, hasAnnotation);
+ });
+ return isSupported.get();
+ }
+
+ @Override
+ public Object resolve(MethodParameter methodParameter, List words) {
+ Object pojo = BeanUtils.instantiateClass(methodParameter.getParameterType());
+ JCommander jCommander = new JCommander();
+ jCommander.addObject(pojo);
+ jCommander.setAcceptUnknownOptions(true);
+ jCommander.parse(words.toArray(new String[words.size()]));
+ return pojo;
+ }
+
+}
diff --git a/src/test/java/org/springframework/shell2/jcommander/FieldCollins.java b/src/test/java/org/springframework/shell2/jcommander/FieldCollins.java
new file mode 100644
index 00000000..541a9f17
--- /dev/null
+++ b/src/test/java/org/springframework/shell2/jcommander/FieldCollins.java
@@ -0,0 +1,45 @@
+package org.springframework.shell2.jcommander;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.beust.jcommander.Parameter;
+
+/**
+ * Created by ericbottard on 15/12/15.
+ */
+public class FieldCollins {
+
+ @Parameter(names = "--name")
+ private String name;
+
+ @Parameter(names = "-level")
+ private int level;
+
+ @Parameter(description = "rest")
+ private List rest = new ArrayList<>();
+
+ public List getRest() {
+ return rest;
+ }
+
+ public void setRest(List rest) {
+ this.rest = rest;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getLevel() {
+ return level;
+ }
+
+ public void setLevel(int level) {
+ this.level = level;
+ }
+}
diff --git a/src/test/java/org/springframework/shell2/jcommander/JCommanderParameterResolverTest.java b/src/test/java/org/springframework/shell2/jcommander/JCommanderParameterResolverTest.java
new file mode 100644
index 00000000..3594cc52
--- /dev/null
+++ b/src/test/java/org/springframework/shell2/jcommander/JCommanderParameterResolverTest.java
@@ -0,0 +1,45 @@
+package org.springframework.shell2.jcommander;
+
+import static java.util.Arrays.asList;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.lang.reflect.Method;
+
+import org.junit.Test;
+
+import org.springframework.core.MethodParameter;
+import org.springframework.util.ReflectionUtils;
+
+/**
+ * Created by ericbottard on 15/12/15.
+ */
+public class JCommanderParameterResolverTest {
+
+ public static final Method COMMAND_METHOD = ReflectionUtils.findMethod(MyLordCommands.class, "genesis", FieldCollins.class);
+
+ private JCommanderParameterResolver resolver = new JCommanderParameterResolver();
+
+ @Test
+ public void testSupportsJCommanderPojos() throws Exception {
+
+ assertThat(resolver.supports(new MethodParameter(COMMAND_METHOD, 0)), is(true));
+ }
+
+ @Test
+ public void testDoesNotSupportsNonJCommanderPojos() throws Exception {
+ Method method = ReflectionUtils.findMethod(MyLordCommands.class, "apocalypse", String.class);
+
+ assertThat(resolver.supports(new MethodParameter(method, 0)), is(false));
+ }
+
+ @Test
+ public void testPojoValuesAreCorrectlySet() {
+ MethodParameter methodParameter = new MethodParameter(COMMAND_METHOD, 0);
+ FieldCollins resolved = (FieldCollins) resolver.resolve(methodParameter, asList("--name foo -level 2 something-else yet-something-else".split(" ")));
+ assertThat(resolved.getName(), is("foo"));
+ assertThat(resolved.getLevel(), is(2));
+ assertThat(resolved.getRest(), contains("something-else", "yet-something-else"));
+ }
+}
diff --git a/src/test/java/org/springframework/shell2/jcommander/MyLordCommands.java b/src/test/java/org/springframework/shell2/jcommander/MyLordCommands.java
new file mode 100644
index 00000000..2158c8bb
--- /dev/null
+++ b/src/test/java/org/springframework/shell2/jcommander/MyLordCommands.java
@@ -0,0 +1,16 @@
+package org.springframework.shell2.jcommander;
+
+/**
+ * Created by ericbottard on 15/12/15.
+ */
+public class MyLordCommands {
+
+ public void genesis(FieldCollins fieldCollins) {
+
+ }
+
+ public void apocalypse(String param) {
+
+ }
+
+}