Skip to content

Commit db567c2

Browse files
therepanicfmbenhassine
authored andcommitted
Fix defaultValue handling for primitive Option parameters
Fixes a case where defaultValue was ignored for primitive option types. Closes: gh-1314 Signed-off-by: Andrey Litvitski <andrey1010102008@gmail.com>
1 parent 0ece35e commit db567c2

2 files changed

Lines changed: 82 additions & 11 deletions

File tree

spring-shell-core/src/main/java/org/springframework/shell/core/command/adapter/MethodInvokerCommandAdapter.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
*
4646
* @author Mahmoud Ben Hassine
4747
* @author David Pilar
48+
* @author Andrey Litvitski
4849
* @since 4.0.0
4950
*/
5051
public class MethodInvokerCommandAdapter extends AbstractCommand {
@@ -157,23 +158,21 @@ private List<Object> prepareArguments(CommandContext commandContext) {
157158
}
158159
else {
159160
Class<?> parameterType = parameterTypes[i];
160-
// check if the option type is primitive or not
161-
if (!parameterType.isPrimitive()) {
162-
// try to convert default value if present
163-
String defaultValue = optionAnnotation.defaultValue();
164-
if (!defaultValue.isEmpty()) {
165-
Object value = this.conversionService.convert(defaultValue, parameterType);
166-
args.add(value);
161+
String defaultValue = optionAnnotation.defaultValue();
162+
if (!defaultValue.isEmpty()) {
163+
Object value = this.conversionService.convert(defaultValue, parameterType);
164+
args.add(value);
165+
}
166+
else {
167+
if (parameterType.isPrimitive()) {
168+
// for primitive types, add default value of the primitive
169+
args.add(Utils.getDefaultValueForPrimitiveType(parameterType));
167170
}
168171
else {
169172
// for non-primitive types, add null
170173
args.add(null);
171174
}
172175
}
173-
else {
174-
// for primitive types, add default value of the primitive
175-
args.add(Utils.getDefaultValueForPrimitiveType(parameterType));
176-
}
177176
}
178177
}
179178
continue;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2025-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.shell.core.command.adapter;
17+
18+
import java.io.PrintWriter;
19+
import java.io.StringWriter;
20+
import java.lang.reflect.Method;
21+
22+
import jakarta.validation.Validation;
23+
import jakarta.validation.Validator;
24+
import org.junit.jupiter.api.Test;
25+
import org.mockito.Mockito;
26+
27+
import org.springframework.core.convert.support.DefaultConversionService;
28+
import org.springframework.shell.core.command.CommandContext;
29+
import org.springframework.shell.core.command.ExitStatus;
30+
import org.springframework.shell.core.command.annotation.Option;
31+
32+
import static org.assertj.core.api.Assertions.assertThat;
33+
34+
/**
35+
* @author Andrey Litvitski
36+
*/
37+
class MethodInvokerCommandAdapterDefaultValueTests {
38+
39+
private static class Target {
40+
41+
int seen;
42+
43+
public void run(@Option(longName = "retries", defaultValue = "3") int retries) {
44+
this.seen = retries;
45+
}
46+
47+
}
48+
49+
@Test
50+
void optionDefaultValueIsUsedForPrimitiveWhenOptionMissing() throws Exception {
51+
Target target = new Target();
52+
Method method = Target.class.getDeclaredMethod("run", int.class);
53+
54+
DefaultConversionService conversionService = new DefaultConversionService();
55+
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
56+
57+
CommandContext ctx = Mockito.mock(CommandContext.class);
58+
Mockito.when(ctx.getOptionByLongName("retries")).thenReturn(null);
59+
60+
StringWriter out = new StringWriter();
61+
Mockito.when(ctx.outputWriter()).thenReturn(new PrintWriter(out));
62+
63+
MethodInvokerCommandAdapter adapter = new MethodInvokerCommandAdapter("name", "desc", "group", "help", false,
64+
method, target, conversionService, validator);
65+
66+
ExitStatus status = adapter.doExecute(ctx);
67+
68+
assertThat(status).isEqualTo(ExitStatus.OK);
69+
assertThat(target.seen).isEqualTo(3);
70+
}
71+
72+
}

0 commit comments

Comments
 (0)