Skip to content

Commit

Permalink
Fix remkop#1767 - NPE on OptionSpec.getValue()
Browse files Browse the repository at this point in the history
  • Loading branch information
rsenden committed Sep 7, 2022
1 parent 5366db8 commit 77373db
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 2 deletions.
24 changes: 22 additions & 2 deletions src/main/java/picocli/CommandLine.java
Original file line number Diff line number Diff line change
Expand Up @@ -6023,6 +6023,15 @@ public interface ISetter {
* @throws Exception internally, picocli call sites will catch any exceptions thrown from here and rethrow them wrapped in a PicocliException */
<T> T set(T value) throws Exception;
}
/** Optional interface that can be implemented by {@link IGetter} implementations to
* indicate whether the {@link IGetter#get()} method is accessible.
*/
public interface IGetterAccessChecker {
/** Check whether the {@link IGetter#get()} method is accessible.
*
* @return true if the {@link IGetter#get()} method is accessible, false otherwise */
boolean isGetterAccessible();
}

/**
* This class provides a case-aware Linked HashMap. Supports both case-sensitive and case-insensitive modes.
Expand Down Expand Up @@ -9169,6 +9178,9 @@ private String defaultValueFromProvider() {

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

static class FieldBinding implements IGetter, ISetter {
static class FieldBinding implements IGetter, IGetterAccessChecker, ISetter {
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 boolean isGetterAccessible() {
try { return scope!=null && scope.get()!=null; }
catch (Exception ex) { return false; }
}
public <T> T get() throws PicocliException {
Object obj;
try { obj = scope.get(); }
Expand Down Expand Up @@ -12051,7 +12067,7 @@ public String toString() {
field.getDeclaringClass().getName(), field.getName());
}
}
static class MethodBinding implements IGetter, ISetter {
static class MethodBinding implements IGetter, IGetterAccessChecker, ISetter {
private final IScope scope;
private final Method method;
private final CommandSpec spec;
Expand All @@ -12061,6 +12077,10 @@ static class MethodBinding implements IGetter, ISetter {
this.method = method;
this.spec = spec;
}
public boolean isGetterAccessible() {
try { return scope!=null && scope.get()!=null; }
catch (Exception ex) { return false; }
}
@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 77373db

Please sign in to comment.