Skip to content

Commit

Permalink
Fix #1767 - NPE on OptionSpec.getValue()
Browse files Browse the repository at this point in the history
  • Loading branch information
rsenden authored and remkop committed Sep 11, 2022
1 parent e3901e3 commit bd7dcbc
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 2 deletions.
35 changes: 33 additions & 2 deletions src/main/java/picocli/CommandLine.java
Original file line number Diff line number Diff line change
Expand Up @@ -5995,6 +5995,15 @@ private Model() {}
* @since 4.0
*/
public interface IScope extends IGetter, ISetter {}

/** This interface provides access to an {@link IScope} instance.
*/
public interface IScoped {
/** Get the {@link IScope} instance.
*
* @return {@link IScope} instance */
IScope getScope();
}

/** Customizable getter for obtaining the current value of an option or positional parameter.
* When an option or positional parameter is matched on the command line, its getter or setter is invoked to capture the value.
Expand Down Expand Up @@ -9166,9 +9175,25 @@ private String defaultValueFromProvider() {
* @return whether this argument applies to all descendent subcommands of the command where it is defined
* @since 4.3 */
public ScopeType scopeType() { return scopeType; }

/** Check whether the {@link #getValue()} method is able to get an actual value from the current {@link #getter()}. */
public boolean isValueGettable() {
if (getter instanceof IScoped) {
IScoped scoped = (IScoped) getter;
IScope scope = scoped.getScope();
try {
Object obj = scope.get();
return obj != null;
} catch (Exception e) {
return false;
}
}
return true;
}

/** Returns the current value of this argument. Delegates to the current {@link #getter()}. */
public <T> T getValue() throws PicocliException {
if ( !isValueGettable() ) { return null; }
try {
return getter.<T>get();
} catch (PicocliException ex) { throw ex;
Expand Down Expand Up @@ -12018,11 +12043,14 @@ private static UnmatchedArgsBinding buildUnmatchedForMember(final IAnnotatedElem
}
}

static class FieldBinding implements IGetter, ISetter {
static class FieldBinding implements IGetter, ISetter, IScoped {
private final IScope scope;
private final Field field;
FieldBinding(Object scope, Field field) { this(ObjectScope.asScope(scope), field); }
FieldBinding(IScope scope, Field field) { this.scope = scope; this.field = field; }
public IScope getScope() {
return scope;
}
public <T> T get() throws PicocliException {
Object obj;
try { obj = scope.get(); }
Expand Down Expand Up @@ -12051,7 +12079,7 @@ public String toString() {
field.getDeclaringClass().getName(), field.getName());
}
}
static class MethodBinding implements IGetter, ISetter {
static class MethodBinding implements IGetter, ISetter, IScoped {
private final IScope scope;
private final Method method;
private final CommandSpec spec;
Expand All @@ -12061,6 +12089,9 @@ static class MethodBinding implements IGetter, ISetter {
this.method = method;
this.spec = spec;
}
public IScope getScope() {
return scope;
}
@SuppressWarnings("unchecked") public <T> T get() { return (T) currentValue; }
public <T> T set(T value) throws PicocliException {
Object obj;
Expand Down
41 changes: 41 additions & 0 deletions src/test/java/picocli/Issue1767.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package picocli;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static picocli.CommandLine.ScopeType.INHERIT;

import java.util.concurrent.Callable;

import org.junit.Test;

import picocli.CommandLine.ArgGroup;
import picocli.CommandLine.Command;
import picocli.CommandLine.IFactory;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Option;
import picocli.CommandLine.Spec;

public class Issue1767 {
@Command(name = "test")
static class TestCommand implements Callable<Integer> {
@ArgGroup TestArgGroup testArgGroup;
@Spec CommandSpec spec;

public static class TestArgGroup {
@Option(names = "-r")
public Integer option1;
}

@Override
public Integer call() throws Exception {
Integer value = spec.options().get(0).getValue();
return value==null ? 0 : value;
}
}

@Test
public void testIssue1772() {
assertEquals(5, new CommandLine(new TestCommand()).execute("-r", "5"));
assertEquals(0, new CommandLine(new TestCommand()).execute());
}
}

0 comments on commit bd7dcbc

Please sign in to comment.