Fix option type parsing
- In `CommandRegistration` add `ResolvableType` for `OptionSpec` giving more spesific handling of a type. - In `CommandParser` handle source and target types so that we have generics with `List`, `Set` and arrays working better. - In `HandlerMethodArgumentResolver` add better handling for `ConversionService` for generic types. - In `StandardMethodTargetRegistrar` add better types via `ResolvableType` now that `CommandRegistration` support it. - In `OptionConversionCommands` remove converter from `String` to `Set` as now things should work as is if generic in a `Set` has a converter. - Backport #694 #699 - Fixes #700
This commit is contained in:
@@ -24,8 +24,10 @@ import jakarta.validation.Validator;
|
||||
import org.jline.terminal.Terminal;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
@@ -253,7 +255,13 @@ public interface CommandExecution {
|
||||
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, Message<?> message) throws Exception {
|
||||
return conversionService.convert(paramValues.get(parameter.getParameterName()), parameter.getParameterType());
|
||||
Object source = paramValues.get(parameter.getParameterName());
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
TypeDescriptor sourceType = new TypeDescriptor(ResolvableType.forClass(source.getClass()), null, null);
|
||||
TypeDescriptor targetType = new TypeDescriptor(parameter);
|
||||
return conversionService.convert(source, sourceType, targetType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -175,13 +175,27 @@ public interface CommandRegistration {
|
||||
OptionSpec shortNames(Character... names);
|
||||
|
||||
/**
|
||||
* Define a type for an option.
|
||||
* Define a type for an option. This method is a shortcut for
|
||||
* {@link #type(ResolvableType)} which is a preferred way to
|
||||
* define type with generics. Will override one from
|
||||
* {@link #type(ResolvableType)}.
|
||||
*
|
||||
* @param type the type
|
||||
* @return option spec for chaining
|
||||
* @see #type(ResolvableType)
|
||||
*/
|
||||
OptionSpec type(Type type);
|
||||
|
||||
/**
|
||||
* Define a {@link ResolvableType} for an option. This method is
|
||||
* a preferred way to define type with generics. Will override one
|
||||
* from {@link #type(Type)}.
|
||||
*
|
||||
* @param type the resolvable type
|
||||
* @return option spec for chaining
|
||||
*/
|
||||
OptionSpec type(ResolvableType type);
|
||||
|
||||
/**
|
||||
* Define a {@code description} for an option.
|
||||
*
|
||||
@@ -817,6 +831,12 @@ public interface CommandRegistration {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionSpec type(ResolvableType type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionSpec description(String description) {
|
||||
this.description = description;
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.shell.command.CommandOption;
|
||||
import org.springframework.shell.command.CommandRegistration;
|
||||
@@ -204,7 +205,8 @@ public interface Parser {
|
||||
optionResults.add(OptionResult.of(o, null));
|
||||
}
|
||||
else {
|
||||
Object value = convertOptionType(o, asdf);
|
||||
Object toConvertValue = asdf.size() == 1 ? asdf.get(0) : asdf;
|
||||
Object value = convertOptionType(o, toConvertValue);
|
||||
optionResults.add(OptionResult.of(o, value));
|
||||
}
|
||||
|
||||
@@ -362,8 +364,11 @@ public interface Parser {
|
||||
return true;
|
||||
}
|
||||
if (conversionService != null && option.getType() != null && value != null) {
|
||||
if (conversionService.canConvert(value.getClass(), option.getType().getRawClass())) {
|
||||
value = conversionService.convert(value, option.getType().getRawClass());
|
||||
Object source = value;
|
||||
TypeDescriptor sourceType = new TypeDescriptor(ResolvableType.forClass(source.getClass()), null, null);
|
||||
TypeDescriptor targetType = new TypeDescriptor(option.getType(), null, null);
|
||||
if (conversionService.canConvert(sourceType, targetType)) {
|
||||
value = conversionService.convert(source, sourceType, targetType);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
|
||||
Reference in New Issue
Block a user