Rework bean handling
- Lot of rework to move better model to work around bean cycles - Remove use of @Lazy - Move StandardAPIAutoConfiguration to autoconfig package - Remove some of a direct ObjectProvider use in constructors - Adds spring-native support with most of a things working out of a box - Relates #324 - Relates #329 - Relates #323
This commit is contained in:
@@ -18,8 +18,6 @@ package org.springframework.shell.boot;
|
||||
import org.jline.reader.LineReader;
|
||||
import org.jline.reader.Parser;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -33,27 +31,30 @@ import org.springframework.shell.jline.ScriptShellApplicationRunner;
|
||||
import static org.springframework.shell.jline.InteractiveShellApplicationRunner.SPRING_SHELL_INTERACTIVE;
|
||||
import static org.springframework.shell.jline.ScriptShellApplicationRunner.SPRING_SHELL_SCRIPT;
|
||||
|
||||
@Configuration
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class ApplicationRunnerAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
private Shell shell;
|
||||
|
||||
@Autowired
|
||||
private PromptProvider promptProvider;
|
||||
|
||||
@Autowired
|
||||
private LineReader lineReader;
|
||||
|
||||
public ApplicationRunnerAutoConfiguration(Shell shell, PromptProvider promptProvider, LineReader lineReader) {
|
||||
this.shell = shell;
|
||||
this.promptProvider = promptProvider;
|
||||
this.lineReader = lineReader;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = SPRING_SHELL_INTERACTIVE, value = InteractiveShellApplicationRunner.ENABLED, havingValue = "true", matchIfMissing = true)
|
||||
public ApplicationRunner interactiveApplicationRunner(Environment environment) {
|
||||
public InteractiveShellApplicationRunner interactiveApplicationRunner(Environment environment) {
|
||||
return new InteractiveShellApplicationRunner(lineReader, promptProvider, shell, environment);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = SPRING_SHELL_SCRIPT, value = ScriptShellApplicationRunner.ENABLED, havingValue = "true", matchIfMissing = true)
|
||||
public ApplicationRunner scriptApplicationRunner(Parser parser, ConfigurableEnvironment environment) {
|
||||
public ScriptShellApplicationRunner scriptApplicationRunner(Parser parser, ConfigurableEnvironment environment) {
|
||||
return new ScriptShellApplicationRunner(parser, shell, environment);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,9 @@ public class CommandRegistryAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public CommandRegistry commandRegistry(
|
||||
ObjectProvider<MethodTargetRegistrar> methodTargerRegistrars) {
|
||||
ObjectProvider<MethodTargetRegistrar> methodTargetRegistrars) {
|
||||
ConfigurableCommandRegistry registry = new ConfigurableCommandRegistry();
|
||||
methodTargerRegistrars.orderedStream().forEach(resolver -> {
|
||||
methodTargetRegistrars.orderedStream().forEach(resolver -> {
|
||||
resolver.register(registry);
|
||||
});
|
||||
return registry;
|
||||
|
||||
@@ -31,7 +31,7 @@ import org.springframework.shell.CompletionContext;
|
||||
import org.springframework.shell.CompletionProposal;
|
||||
import org.springframework.shell.Shell;
|
||||
|
||||
@Configuration
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class CompleterAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.context.annotation.Bean;
|
||||
*
|
||||
* @author Eric Bottard
|
||||
*/
|
||||
@Configuration
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ JCommander.class, JCommanderParameterResolver.class })
|
||||
public class JCommanderParameterResolverAutoConfiguration {
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class JLineAutoConfiguration {
|
||||
|
||||
@Configuration
|
||||
|
||||
@@ -37,7 +37,7 @@ import org.springframework.shell.jline.PromptProvider;
|
||||
* @author Eric Bottard
|
||||
* @author Florent Biville
|
||||
*/
|
||||
@Configuration
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class JLineShellAutoConfiguration {
|
||||
|
||||
@Bean(destroyMethod = "close")
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.jline.utils.AttributedString;
|
||||
import org.jline.utils.AttributedStringBuilder;
|
||||
import org.jline.utils.AttributedStyle;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -37,32 +36,36 @@ import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.shell.CommandRegistry;
|
||||
|
||||
@Configuration
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class LineReaderAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
private Terminal terminal;
|
||||
|
||||
@Autowired
|
||||
private Completer completer;
|
||||
|
||||
@Autowired
|
||||
private Parser parser;
|
||||
|
||||
@Autowired
|
||||
private CommandRegistry commandRegistry;
|
||||
|
||||
@Autowired
|
||||
private org.jline.reader.History jLineHistory;
|
||||
|
||||
@Value("${spring.application.name:spring-shell}.log")
|
||||
private String historyPath;
|
||||
|
||||
public LineReaderAutoConfiguration(Terminal terminal, Completer completer, Parser parser,
|
||||
CommandRegistry commandRegistry, org.jline.reader.History jLineHistory) {
|
||||
this.terminal = terminal;
|
||||
this.completer = completer;
|
||||
this.parser = parser;
|
||||
this.commandRegistry = commandRegistry;
|
||||
this.jLineHistory = jLineHistory;
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void onContextClosedEvent(ContextClosedEvent event) throws IOException {
|
||||
jLineHistory.save();
|
||||
}
|
||||
|
||||
@Value("${spring.application.name:spring-shell}.log")
|
||||
private String historyPath;
|
||||
|
||||
@Bean
|
||||
public LineReader lineReader() {
|
||||
LineReaderBuilder lineReaderBuilder = LineReaderBuilder.builder()
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.springframework.shell.boot;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.shell.ParameterResolver;
|
||||
import org.springframework.shell.standard.StandardParameterResolver;
|
||||
import org.springframework.shell.standard.ValueProvider;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class ParameterResolverAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public ParameterResolver standardParameterResolver(@Qualifier("spring-shell") ConversionService conversionService,
|
||||
ObjectProvider<ValueProvider> valueProviders) {
|
||||
Set<ValueProvider> collect = valueProviders.orderedStream().collect(Collectors.toSet());
|
||||
return new StandardParameterResolver(conversionService, collect);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,11 +19,7 @@ package org.springframework.shell.boot;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -33,6 +29,7 @@ import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.ConverterFactory;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.shell.CommandRegistry;
|
||||
import org.springframework.shell.ResultHandler;
|
||||
import org.springframework.shell.ResultHandlerService;
|
||||
import org.springframework.shell.Shell;
|
||||
@@ -42,7 +39,7 @@ import org.springframework.shell.result.ResultHandlerConfig;
|
||||
/**
|
||||
* Creates supporting beans for running the Shell
|
||||
*/
|
||||
@Configuration
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(ResultHandlerConfig.class)
|
||||
public class SpringShellAutoConfiguration {
|
||||
|
||||
@@ -66,12 +63,6 @@ public class SpringShellAutoConfiguration {
|
||||
return defaultConversionService;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(Validator.class)
|
||||
public Validator validator() {
|
||||
return Validation.buildDefaultValidatorFactory().getValidator();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ResultHandlerService resultHandlerService(Set<ResultHandler<?>> resultHandlers) {
|
||||
GenericResultHandlerService service = new GenericResultHandlerService();
|
||||
@@ -82,7 +73,7 @@ public class SpringShellAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Shell shell(ResultHandlerService resultHandlerService) {
|
||||
return new Shell(resultHandlerService);
|
||||
public Shell shell(ResultHandlerService resultHandlerService, CommandRegistry commandRegistry) {
|
||||
return new Shell(resultHandlerService, commandRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,27 +14,28 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.shell.standard;
|
||||
package org.springframework.shell.boot;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.shell.CommandRegistry;
|
||||
import org.springframework.shell.MethodTargetRegistrar;
|
||||
import org.springframework.shell.ParameterResolver;
|
||||
import org.springframework.shell.standard.CommandValueProvider;
|
||||
import org.springframework.shell.standard.EnumValueProvider;
|
||||
import org.springframework.shell.standard.FileValueProvider;
|
||||
import org.springframework.shell.standard.StandardMethodTargetRegistrar;
|
||||
import org.springframework.shell.standard.ValueProvider;
|
||||
|
||||
/**
|
||||
* Sets up all required beans for supporting the standard Shell API.
|
||||
*
|
||||
* @author Eric Bottard
|
||||
*/
|
||||
@Configuration
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class StandardAPIAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public ValueProvider commandValueProvider(@Lazy CommandRegistry commandRegistry) {
|
||||
public ValueProvider commandValueProvider(CommandRegistry commandRegistry) {
|
||||
return new CommandValueProvider(commandRegistry);
|
||||
}
|
||||
|
||||
@@ -52,9 +53,4 @@ public class StandardAPIAutoConfiguration {
|
||||
public MethodTargetRegistrar standardMethodTargetResolver() {
|
||||
return new StandardMethodTargetRegistrar();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ParameterResolver standardParameterResolver(@Qualifier("spring-shell") ConversionService conversionService) {
|
||||
return new StandardParameterResolver(conversionService);
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.shell.boot;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jline.reader.Parser;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
@@ -26,8 +24,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.shell.ParameterResolver;
|
||||
import org.springframework.shell.Shell;
|
||||
import org.springframework.shell.result.ThrowableResultHandler;
|
||||
import org.springframework.shell.standard.commands.Clear;
|
||||
import org.springframework.shell.standard.commands.Help;
|
||||
import org.springframework.shell.standard.commands.History;
|
||||
@@ -40,15 +37,15 @@ import org.springframework.shell.standard.commands.Stacktrace;
|
||||
*
|
||||
* @author Eric Bottard
|
||||
*/
|
||||
@Configuration
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ Help.Command.class })
|
||||
public class StandardCommandsAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(Help.Command.class)
|
||||
@ConditionalOnProperty(prefix = "spring.shell.command.help", value = "enabled", havingValue = "true", matchIfMissing = true)
|
||||
public Help help(List<ParameterResolver> parameterResolvers) {
|
||||
return new Help(parameterResolvers);
|
||||
public Help help() {
|
||||
return new Help();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -68,15 +65,15 @@ public class StandardCommandsAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(Stacktrace.Command.class)
|
||||
@ConditionalOnProperty(prefix = "spring.shell.command.stacktrace", value = "enabled", havingValue = "true", matchIfMissing = true)
|
||||
public Stacktrace stacktrace() {
|
||||
return new Stacktrace();
|
||||
public Stacktrace stacktrace(ObjectProvider<ThrowableResultHandler> throwableResultHandler) {
|
||||
return new Stacktrace(throwableResultHandler);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(Script.Command.class)
|
||||
@ConditionalOnProperty(prefix = "spring.shell.command.script", value = "enabled", havingValue = "true", matchIfMissing = true)
|
||||
public Script script(ObjectProvider<Shell> shell, Parser parser) {
|
||||
return new Script(shell, parser);
|
||||
public Script script(Parser parser) {
|
||||
return new Script(parser);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -7,4 +7,6 @@ org.springframework.shell.boot.CompleterAutoConfiguration,\
|
||||
org.springframework.shell.boot.JLineAutoConfiguration,\
|
||||
org.springframework.shell.boot.JLineShellAutoConfiguration,\
|
||||
org.springframework.shell.boot.JCommanderParameterResolverAutoConfiguration,\
|
||||
org.springframework.shell.boot.ParameterResolverAutoConfiguration,\
|
||||
org.springframework.shell.boot.StandardAPIAutoConfiguration,\
|
||||
org.springframework.shell.boot.StandardCommandsAutoConfiguration
|
||||
|
||||
@@ -30,7 +30,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.ValidatorFactory;
|
||||
|
||||
@@ -70,10 +69,9 @@ public class Shell {
|
||||
@Autowired
|
||||
protected ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private CommandRegistry commandRegistry;
|
||||
|
||||
private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
private Validator validator = Utils.defaultValidator();
|
||||
|
||||
protected Map<String, MethodTarget> methodTargets = new HashMap<>();
|
||||
|
||||
@@ -85,8 +83,9 @@ public class Shell {
|
||||
*/
|
||||
protected static final Object UNRESOLVED = new Object();
|
||||
|
||||
public Shell(ResultHandlerService resultHandlerService) {
|
||||
public Shell(ResultHandlerService resultHandlerService, CommandRegistry commandRegistry) {
|
||||
this.resultHandlerService = resultHandlerService;
|
||||
this.commandRegistry = commandRegistry;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
|
||||
@@ -25,6 +25,10 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.ValidatorFactory;
|
||||
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.MethodParameter;
|
||||
|
||||
@@ -100,4 +104,30 @@ public class Utils {
|
||||
.collect(Collectors.toList());
|
||||
return words;
|
||||
}
|
||||
|
||||
private final static ValidatorFactory DEFAULT_VALIDATOR_FACTORY;
|
||||
private final static Validator DEFAULT_VALIDATOR;
|
||||
|
||||
static {
|
||||
DEFAULT_VALIDATOR_FACTORY = Validation.buildDefaultValidatorFactory();
|
||||
DEFAULT_VALIDATOR = DEFAULT_VALIDATOR_FACTORY.getValidator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a default shared validation factory.
|
||||
*
|
||||
* @return default validation factory
|
||||
*/
|
||||
public static ValidatorFactory defaultValidatorFactory() {
|
||||
return DEFAULT_VALIDATOR_FACTORY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a default shared validator.
|
||||
*
|
||||
* @return default validator
|
||||
*/
|
||||
public static Validator defaultValidator() {
|
||||
return DEFAULT_VALIDATOR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.shell.result;
|
||||
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.jline.utils.AttributedCharSequence;
|
||||
|
||||
import org.springframework.shell.ResultHandler;
|
||||
@@ -27,6 +28,10 @@ import org.springframework.shell.ResultHandler;
|
||||
*/
|
||||
public class AttributedCharSequenceResultHandler extends TerminalAwareResultHandler<AttributedCharSequence> {
|
||||
|
||||
public AttributedCharSequenceResultHandler(Terminal terminal) {
|
||||
super(terminal);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHandleResult(AttributedCharSequence result) {
|
||||
terminal.writer().println(result.toAnsi(terminal));
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.shell.result;
|
||||
|
||||
import org.jline.terminal.Terminal;
|
||||
|
||||
import org.springframework.shell.ResultHandler;
|
||||
|
||||
/**
|
||||
@@ -26,6 +28,10 @@ import org.springframework.shell.ResultHandler;
|
||||
*/
|
||||
public class DefaultResultHandler extends TerminalAwareResultHandler<Object> {
|
||||
|
||||
public DefaultResultHandler(Terminal terminal) {
|
||||
super(terminal);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHandleResult(Object result) {
|
||||
terminal.writer().println(String.valueOf(result));
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.stream.StreamSupport;
|
||||
import javax.validation.ElementKind;
|
||||
import javax.validation.Path;
|
||||
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.jline.utils.AttributedString;
|
||||
import org.jline.utils.AttributedStringBuilder;
|
||||
import org.jline.utils.AttributedStyle;
|
||||
@@ -43,6 +44,10 @@ import org.springframework.shell.Utils;
|
||||
public class ParameterValidationExceptionResultHandler
|
||||
extends TerminalAwareResultHandler<ParameterValidationException> {
|
||||
|
||||
public ParameterValidationExceptionResultHandler(Terminal terminal) {
|
||||
super(terminal);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private List<ParameterResolver> parameterResolvers;
|
||||
|
||||
|
||||
@@ -16,10 +16,15 @@
|
||||
|
||||
package org.springframework.shell.result;
|
||||
|
||||
import org.jline.terminal.Terminal;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.shell.CommandRegistry;
|
||||
import org.springframework.shell.TerminalSizeAware;
|
||||
import org.springframework.shell.jline.InteractiveShellApplicationRunner;
|
||||
|
||||
/**
|
||||
* Used for explicit configuration of {@link org.springframework.shell.ResultHandler}s.
|
||||
@@ -32,28 +37,29 @@ public class ResultHandlerConfig {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(TerminalSizeAware.class)
|
||||
public TerminalSizeAwareResultHandler terminalSizeAwareResultHandler() {
|
||||
return new TerminalSizeAwareResultHandler();
|
||||
public TerminalSizeAwareResultHandler terminalSizeAwareResultHandler(Terminal terminal) {
|
||||
return new TerminalSizeAwareResultHandler(terminal);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AttributedCharSequenceResultHandler attributedCharSequenceResultHandler() {
|
||||
return new AttributedCharSequenceResultHandler();
|
||||
public AttributedCharSequenceResultHandler attributedCharSequenceResultHandler(Terminal terminal) {
|
||||
return new AttributedCharSequenceResultHandler(terminal);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DefaultResultHandler defaultResultHandler() {
|
||||
return new DefaultResultHandler();
|
||||
public DefaultResultHandler defaultResultHandler(Terminal terminal) {
|
||||
return new DefaultResultHandler(terminal);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ParameterValidationExceptionResultHandler parameterValidationExceptionResultHandler() {
|
||||
return new ParameterValidationExceptionResultHandler();
|
||||
public ParameterValidationExceptionResultHandler parameterValidationExceptionResultHandler(Terminal terminal) {
|
||||
return new ParameterValidationExceptionResultHandler(terminal);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ThrowableResultHandler throwableResultHandler() {
|
||||
return new ThrowableResultHandler();
|
||||
public ThrowableResultHandler throwableResultHandler(Terminal terminal, CommandRegistry commandRegistry,
|
||||
ObjectProvider<InteractiveShellApplicationRunner> interactiveApplicationRunner) {
|
||||
return new ThrowableResultHandler(terminal, commandRegistry, interactiveApplicationRunner);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ package org.springframework.shell.result;
|
||||
|
||||
import org.jline.terminal.Terminal;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.shell.ResultHandler;
|
||||
|
||||
/**
|
||||
@@ -28,10 +26,10 @@ import org.springframework.shell.ResultHandler;
|
||||
* @author Eric Bottard
|
||||
*/
|
||||
public abstract class TerminalAwareResultHandler<T> implements ResultHandler<T> {
|
||||
|
||||
protected Terminal terminal;
|
||||
|
||||
@Autowired @Lazy
|
||||
public void setTerminal(Terminal terminal) {
|
||||
protected TerminalAwareResultHandler(Terminal terminal) {
|
||||
this.terminal = terminal;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.shell.result;
|
||||
|
||||
import org.jline.terminal.Terminal;
|
||||
|
||||
import org.springframework.shell.TerminalSizeAware;
|
||||
|
||||
/**
|
||||
@@ -25,6 +27,9 @@ import org.springframework.shell.TerminalSizeAware;
|
||||
*/
|
||||
public class TerminalSizeAwareResultHandler extends TerminalAwareResultHandler<TerminalSizeAware> {
|
||||
|
||||
public TerminalSizeAwareResultHandler(Terminal terminal) {
|
||||
super(terminal);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHandleResult(TerminalSizeAware result) {
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
|
||||
package org.springframework.shell.result;
|
||||
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.jline.utils.AttributedString;
|
||||
import org.jline.utils.AttributedStringBuilder;
|
||||
import org.jline.utils.AttributedStyle;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.shell.CommandRegistry;
|
||||
import org.springframework.shell.ResultHandler;
|
||||
import org.springframework.shell.jline.InteractiveShellApplicationRunner;
|
||||
@@ -43,11 +43,16 @@ public class ThrowableResultHandler extends TerminalAwareResultHandler<Throwable
|
||||
|
||||
private Throwable lastError;
|
||||
|
||||
@Autowired @Lazy
|
||||
private CommandRegistry commandRegistry;
|
||||
|
||||
@Autowired @Lazy
|
||||
private InteractiveShellApplicationRunner interactiveRunner;
|
||||
private ObjectProvider<InteractiveShellApplicationRunner> interactiveRunner;
|
||||
|
||||
public ThrowableResultHandler(Terminal terminal, CommandRegistry commandRegistry,
|
||||
ObjectProvider<InteractiveShellApplicationRunner> interactiveRunner) {
|
||||
super(terminal);
|
||||
this.commandRegistry = commandRegistry;
|
||||
this.interactiveRunner = interactiveRunner;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHandleResult(Throwable result) {
|
||||
@@ -55,7 +60,7 @@ public class ThrowableResultHandler extends TerminalAwareResultHandler<Throwable
|
||||
String toPrint = StringUtils.hasLength(result.getMessage()) ? result.getMessage() : result.toString();
|
||||
terminal.writer().println(new AttributedString(toPrint,
|
||||
AttributedStyle.DEFAULT.foreground(AttributedStyle.RED)).toAnsi());
|
||||
if (interactiveRunner.isEnabled() && commandRegistry.listCommands().containsKey(DETAILS_COMMAND_NAME)) {
|
||||
if (interactiveRunner.getIfAvailable().isEnabled() && commandRegistry.listCommands().containsKey(DETAILS_COMMAND_NAME)) {
|
||||
terminal.writer().println(
|
||||
new AttributedStringBuilder()
|
||||
.append("Details of the error have been omitted. You can use the ", AttributedStyle.DEFAULT.foreground(AttributedStyle.RED))
|
||||
@@ -65,7 +70,7 @@ public class ThrowableResultHandler extends TerminalAwareResultHandler<Throwable
|
||||
);
|
||||
}
|
||||
terminal.writer().flush();
|
||||
if (!interactiveRunner.isEnabled()) {
|
||||
if (!interactiveRunner.getIfAvailable().isEnabled()) {
|
||||
if (result instanceof RuntimeException) {
|
||||
throw (RuntimeException) result;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.ValidatorFactory;
|
||||
import javax.validation.metadata.BeanDescriptor;
|
||||
@@ -43,6 +42,7 @@ import org.springframework.shell.CompletionContext;
|
||||
import org.springframework.shell.CompletionProposal;
|
||||
import org.springframework.shell.ParameterDescription;
|
||||
import org.springframework.shell.ParameterResolver;
|
||||
import org.springframework.shell.Utils;
|
||||
import org.springframework.shell.ValueResult;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
@@ -59,7 +59,7 @@ public class JCommanderParameterResolver implements ParameterResolver {
|
||||
private static final Collection<Class<? extends Annotation>> JCOMMANDER_ANNOTATIONS = Arrays.asList(Parameter.class,
|
||||
DynamicParameter.class, ParametersDelegate.class);
|
||||
|
||||
private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
private Validator validator = Utils.defaultValidator();
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setValidatorFactory(ValidatorFactory validatorFactory) {
|
||||
|
||||
@@ -22,13 +22,13 @@ import org.springframework.context.annotation.Import;
|
||||
import org.springframework.shell.boot.JCommanderParameterResolverAutoConfiguration;
|
||||
import org.springframework.shell.boot.JLineShellAutoConfiguration;
|
||||
import org.springframework.shell.boot.SpringShellAutoConfiguration;
|
||||
import org.springframework.shell.boot.StandardAPIAutoConfiguration;
|
||||
import org.springframework.shell.boot.StandardCommandsAutoConfiguration;
|
||||
import org.springframework.shell.samples.jcommander.JCommanderCommands;
|
||||
import org.springframework.shell.samples.standard.Commands;
|
||||
import org.springframework.shell.samples.standard.DynamicCommands;
|
||||
import org.springframework.shell.samples.standard.TableCommands;
|
||||
import org.springframework.shell.standard.FileValueProvider;
|
||||
import org.springframework.shell.standard.StandardAPIAutoConfiguration;
|
||||
|
||||
/**
|
||||
* This class shows how to use the full extent of Spring Shell without relying on Boot auto configuration.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
* Copyright 2017-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,11 +16,9 @@
|
||||
|
||||
package org.springframework.shell.standard.commands;
|
||||
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.jline.utils.InfoCmp;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.shell.standard.AbstractShellComponent;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
|
||||
@@ -28,9 +26,10 @@ import org.springframework.shell.standard.ShellMethod;
|
||||
* ANSI console related commands.
|
||||
*
|
||||
* @author Eric Bottard
|
||||
* @author Janne Valkealahti
|
||||
*/
|
||||
@ShellComponent
|
||||
public class Clear {
|
||||
public class Clear extends AbstractShellComponent {
|
||||
|
||||
/**
|
||||
* Marker interface for beans providing {@literal clear} functionality to the shell.
|
||||
@@ -45,11 +44,11 @@ public class Clear {
|
||||
*/
|
||||
public interface Command {}
|
||||
|
||||
@Autowired @Lazy
|
||||
private Terminal terminal;
|
||||
public Clear() {
|
||||
}
|
||||
|
||||
@ShellMethod("Clear the shell screen.")
|
||||
public void clear() {
|
||||
terminal.puts(InfoCmp.Capability.clear_screen);
|
||||
getTerminal().puts(InfoCmp.Capability.clear_screen);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,21 +29,18 @@ import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.MessageInterpolator;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.ValidatorFactory;
|
||||
import javax.validation.metadata.ConstraintDescriptor;
|
||||
|
||||
import org.jline.utils.AttributedStringBuilder;
|
||||
import org.jline.utils.AttributedStyle;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.shell.Availability;
|
||||
import org.springframework.shell.CommandRegistry;
|
||||
import org.springframework.shell.MethodTarget;
|
||||
import org.springframework.shell.ParameterDescription;
|
||||
import org.springframework.shell.ParameterResolver;
|
||||
import org.springframework.shell.Utils;
|
||||
import org.springframework.shell.standard.AbstractShellComponent;
|
||||
import org.springframework.shell.standard.CommandValueProvider;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
@@ -60,7 +57,7 @@ import static java.util.stream.Collectors.toMap;
|
||||
* @author Eric Bottard
|
||||
*/
|
||||
@ShellComponent
|
||||
public class Help {
|
||||
public class Help extends AbstractShellComponent {
|
||||
|
||||
/**
|
||||
* Marker interface for beans providing {@literal help} functionality to the shell.
|
||||
@@ -80,21 +77,9 @@ public class Help {
|
||||
public interface Command {
|
||||
}
|
||||
|
||||
private final List<ParameterResolver> parameterResolvers;
|
||||
private MessageInterpolator messageInterpolator = Utils.defaultValidatorFactory().getMessageInterpolator();
|
||||
|
||||
private ObjectProvider<CommandRegistry> commandRegistry;
|
||||
|
||||
private MessageInterpolator messageInterpolator = Validation.buildDefaultValidatorFactory()
|
||||
.getMessageInterpolator();
|
||||
|
||||
@Autowired
|
||||
public Help(List<ParameterResolver> parameterResolvers) {
|
||||
this.parameterResolvers = parameterResolvers;
|
||||
}
|
||||
|
||||
@Autowired // ctor injection impossible b/c of circular dependency
|
||||
public void setCommandRegistry(ObjectProvider<CommandRegistry> commandRegistry) {
|
||||
this.commandRegistry = commandRegistry;
|
||||
public Help() {
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
@@ -102,7 +87,6 @@ public class Help {
|
||||
this.messageInterpolator = validatorFactory.getMessageInterpolator();
|
||||
}
|
||||
|
||||
|
||||
@ShellMethod(value = "Display help about available commands.", prefix = "-")
|
||||
public CharSequence help(
|
||||
@ShellOption(defaultValue = ShellOption.NULL, valueProvider = CommandValueProvider.class, value = { "-C",
|
||||
@@ -121,7 +105,7 @@ public class Help {
|
||||
* Return a description of a specific command. Uses a layout inspired by *nix man pages.
|
||||
*/
|
||||
private CharSequence documentCommand(String command) {
|
||||
MethodTarget methodTarget = commandRegistry.getIfAvailable().listCommands().get(command);
|
||||
MethodTarget methodTarget = getCommandRegistry().listCommands().get(command);
|
||||
if (methodTarget == null) {
|
||||
throw new IllegalArgumentException("Unknown command '" + command + "'");
|
||||
}
|
||||
@@ -248,7 +232,7 @@ public class Help {
|
||||
}
|
||||
|
||||
private void documentAliases(AttributedStringBuilder result, String command, MethodTarget methodTarget) {
|
||||
Set<String> aliases = commandRegistry.getIfAvailable().listCommands().entrySet().stream()
|
||||
Set<String> aliases = getCommandRegistry().listCommands().entrySet().stream()
|
||||
.filter(e -> e.getValue().equals(methodTarget))
|
||||
.map(Map.Entry::getKey)
|
||||
.filter(c -> !command.equals(c))
|
||||
@@ -277,7 +261,7 @@ public class Help {
|
||||
}
|
||||
|
||||
private CharSequence listCommands() {
|
||||
Map<String, MethodTarget> commandsByName = commandRegistry.getIfAvailable().listCommands();
|
||||
Map<String, MethodTarget> commandsByName = getCommandRegistry().listCommands();
|
||||
|
||||
SortedMap<String, Map<String, MethodTarget>> commandsByGroupAndName = commandsByName.entrySet().stream()
|
||||
.collect(groupingBy(e -> e.getValue().getGroup(), TreeMap::new, // group by and sort by command group
|
||||
@@ -335,7 +319,7 @@ public class Help {
|
||||
|
||||
private List<ParameterDescription> getParameterDescriptions(MethodTarget methodTarget) {
|
||||
return Utils.createMethodParameters(methodTarget.getMethod())
|
||||
.flatMap(mp -> parameterResolvers.stream().filter(pr -> pr.supports(mp)).limit(1L)
|
||||
.flatMap(mp -> getParameterResolver().filter(pr -> pr.supports(mp)).limit(1L)
|
||||
.flatMap(pr -> pr.describe(mp)))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2017-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.shell.standard.commands;
|
||||
|
||||
import java.io.File;
|
||||
@@ -7,9 +22,8 @@ import java.io.Reader;
|
||||
|
||||
import org.jline.reader.Parser;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.shell.Shell;
|
||||
import org.springframework.shell.jline.FileInputProvider;
|
||||
import org.springframework.shell.standard.AbstractShellComponent;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
|
||||
@@ -17,16 +31,14 @@ import org.springframework.shell.standard.ShellMethod;
|
||||
* A command that can read and execute other commands from a file.
|
||||
*
|
||||
* @author Eric Bottard
|
||||
* @author Janne Valkealahti
|
||||
*/
|
||||
@ShellComponent
|
||||
public class Script {
|
||||
|
||||
private final ObjectProvider<Shell> shell;
|
||||
public class Script extends AbstractShellComponent {
|
||||
|
||||
private final Parser parser;
|
||||
|
||||
public Script(ObjectProvider<Shell> shell, Parser parser) {
|
||||
this.shell = shell;
|
||||
public Script(Parser parser) {
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
@@ -48,7 +60,7 @@ public class Script {
|
||||
public void script(File file) throws IOException {
|
||||
Reader reader = new FileReader(file);
|
||||
try (FileInputProvider inputProvider = new FileInputProvider(reader, parser)) {
|
||||
shell.getIfAvailable().run(inputProvider);
|
||||
getShell().run(inputProvider);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
* Copyright 2017-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,22 +13,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.shell.standard.commands;
|
||||
|
||||
import org.jline.terminal.Terminal;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.shell.result.ThrowableResultHandler;
|
||||
import org.springframework.shell.standard.AbstractShellComponent;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
|
||||
/**
|
||||
* A command to display the full stacktrace when an error occurs.
|
||||
*
|
||||
* @author Eric Bottard
|
||||
* @author Janne Valkealahti
|
||||
*/
|
||||
@ShellComponent
|
||||
public class Stacktrace {
|
||||
public class Stacktrace extends AbstractShellComponent {
|
||||
|
||||
/**
|
||||
* Marker interface for beans providing {@literal stacktrace} functionality to the shell.
|
||||
@@ -43,17 +43,16 @@ public class Stacktrace {
|
||||
*/
|
||||
public interface Command {}
|
||||
|
||||
@Autowired @Lazy
|
||||
private Terminal terminal;
|
||||
|
||||
@Autowired
|
||||
private ThrowableResultHandler throwableResultHandler;
|
||||
private ObjectProvider<ThrowableResultHandler> throwableResultHandler;
|
||||
|
||||
public Stacktrace(ObjectProvider<ThrowableResultHandler> throwableResultHandler) {
|
||||
this.throwableResultHandler = throwableResultHandler;
|
||||
}
|
||||
|
||||
@ShellMethod(key = ThrowableResultHandler.DETAILS_COMMAND_NAME, value = "Display the full stacktrace of the last error.")
|
||||
public void stacktrace() {
|
||||
if (throwableResultHandler.getLastError() != null) {
|
||||
throwableResultHandler.getLastError().printStackTrace(terminal.writer());
|
||||
if (throwableResultHandler.getIfAvailable().getLastError() != null) {
|
||||
throwableResultHandler.getIfAvailable().getLastError().printStackTrace(getTerminal().writer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,8 +117,8 @@ public class HelpTest {
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
public Help help() {
|
||||
return new Help(Collections.singletonList(parameterResolver()));
|
||||
public Help help(CommandRegistry commandRegistry) {
|
||||
return new Help();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -148,7 +148,7 @@ public class HelpTest {
|
||||
|
||||
@Bean
|
||||
public ParameterResolver parameterResolver() {
|
||||
return new StandardParameterResolver(new DefaultConversionService());
|
||||
return new StandardParameterResolver(new DefaultConversionService(), Collections.emptySet());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.shell.standard;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jline.terminal.Terminal;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.shell.CommandRegistry;
|
||||
import org.springframework.shell.ParameterResolver;
|
||||
import org.springframework.shell.Shell;
|
||||
|
||||
/**
|
||||
* Base class helping to build shell components.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*/
|
||||
public class AbstractShellComponent implements ApplicationContextAware, InitializingBean {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private ObjectProvider<Shell> shellProvider;
|
||||
|
||||
private ObjectProvider<Terminal> terminalProvider;
|
||||
|
||||
private ObjectProvider<CommandRegistry> commandRegistryProvider;
|
||||
|
||||
private ObjectProvider<ParameterResolver> parameterResolverProvider;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
shellProvider = applicationContext.getBeanProvider(Shell.class);
|
||||
terminalProvider = applicationContext.getBeanProvider(Terminal.class);
|
||||
commandRegistryProvider = applicationContext.getBeanProvider(CommandRegistry.class);
|
||||
parameterResolverProvider = applicationContext.getBeanProvider(ParameterResolver.class);
|
||||
}
|
||||
|
||||
protected Shell getShell() {
|
||||
return shellProvider.getObject();
|
||||
}
|
||||
|
||||
protected Terminal getTerminal() {
|
||||
return terminalProvider.getObject();
|
||||
}
|
||||
|
||||
protected CommandRegistry getCommandRegistry() {
|
||||
return commandRegistryProvider.getObject();
|
||||
}
|
||||
|
||||
protected Stream<ParameterResolver> getParameterResolver() {
|
||||
return parameterResolverProvider.orderedStream();
|
||||
}
|
||||
}
|
||||
@@ -16,21 +16,32 @@
|
||||
|
||||
package org.springframework.shell.standard;
|
||||
|
||||
import static org.springframework.util.StringUtils.collectionToDelimitedString;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.shell.*;
|
||||
import org.springframework.shell.Availability;
|
||||
import org.springframework.shell.Command;
|
||||
import org.springframework.shell.ConfigurableCommandRegistry;
|
||||
import org.springframework.shell.MethodTarget;
|
||||
import org.springframework.shell.MethodTargetRegistrar;
|
||||
import org.springframework.shell.Utils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.util.StringUtils.collectionToDelimitedString;
|
||||
|
||||
/**
|
||||
* The standard implementation of {@link MethodTargetRegistrar} for new shell
|
||||
* applications, resolves methods annotated with {@link ShellMethod} on
|
||||
@@ -40,13 +51,13 @@ import org.springframework.util.StringUtils;
|
||||
* @author Florent Biville
|
||||
* @author Camilo Gonzalez
|
||||
*/
|
||||
public class StandardMethodTargetRegistrar implements MethodTargetRegistrar {
|
||||
public class StandardMethodTargetRegistrar implements MethodTargetRegistrar, ApplicationContextAware {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private Map<String, MethodTarget> commands = new HashMap<>();
|
||||
|
||||
@Autowired
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.ValidatorFactory;
|
||||
import javax.validation.metadata.MethodDescriptor;
|
||||
@@ -97,6 +96,8 @@ public class StandardParameterResolver implements ParameterResolver {
|
||||
|
||||
private Collection<ValueProvider> valueProviders = new HashSet<>();
|
||||
|
||||
private Validator validator = Utils.defaultValidator();
|
||||
|
||||
/**
|
||||
* A cache from method+input to String representation of actual parameter values. Note
|
||||
* that the converted result is not cached, to allow dynamic computation to happen at
|
||||
@@ -104,24 +105,16 @@ public class StandardParameterResolver implements ParameterResolver {
|
||||
*/
|
||||
private final Map<CacheKey, Map<Parameter, ParameterRawValue>> parameterCache = new ConcurrentReferenceHashMap<>();
|
||||
|
||||
@Autowired
|
||||
public StandardParameterResolver(ConversionService conversionService) {
|
||||
public StandardParameterResolver(ConversionService conversionService, Set<ValueProvider> valueProviders) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setValueProviders(Collection<ValueProvider> valueProviders) {
|
||||
this.valueProviders = valueProviders;
|
||||
}
|
||||
|
||||
private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setValidatorFactory(ValidatorFactory validatorFactory) {
|
||||
this.validator = validatorFactory.getValidator();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean supports(MethodParameter parameter) {
|
||||
boolean optOut = parameter.hasParameterAnnotation(ShellOption.class)
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.shell.standard.StandardAPIAutoConfiguration
|
||||
@@ -17,7 +17,10 @@
|
||||
package org.springframework.shell.standard;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jline.reader.ParsedLine;
|
||||
@@ -33,7 +36,6 @@ import org.springframework.shell.Utils;
|
||||
import org.springframework.shell.ValueResult;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.springframework.shell.ValueResultAsserts.assertThat;
|
||||
@@ -46,12 +48,14 @@ import static org.springframework.util.ReflectionUtils.findMethod;
|
||||
*/
|
||||
public class StandardParameterResolverTest {
|
||||
|
||||
private StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService());
|
||||
// private StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(), Collections.emptySet());
|
||||
|
||||
// Tests for resolution
|
||||
|
||||
@Test
|
||||
public void testParses() throws Exception {
|
||||
StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(),
|
||||
Collections.emptySet());
|
||||
Method method = findMethod(Remote.class, "zap", boolean.class, String.class, String.class, String.class);
|
||||
|
||||
List<String> words = asList("--force --name --foo y".split(" "));
|
||||
@@ -74,6 +78,8 @@ public class StandardParameterResolverTest {
|
||||
|
||||
@Test
|
||||
public void testParsesWithMethodPrefix() throws Exception {
|
||||
StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(),
|
||||
Collections.emptySet());
|
||||
Method method = findMethod(Remote.class, "prefixTest", String.class);
|
||||
|
||||
ValueResult result = resolver.resolve(Utils.createMethodParameter(method, 0),
|
||||
@@ -83,6 +89,8 @@ public class StandardParameterResolverTest {
|
||||
|
||||
@Test
|
||||
public void testParameterSpecifiedTwiceViaDifferentAliases() throws Exception {
|
||||
StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(),
|
||||
Collections.emptySet());
|
||||
Method method = findMethod(Remote.class, "zap", boolean.class, String.class, String.class, String.class);
|
||||
|
||||
assertThatThrownBy(() -> {
|
||||
@@ -95,6 +103,8 @@ public class StandardParameterResolverTest {
|
||||
|
||||
@Test
|
||||
public void testParameterSpecifiedTwiceViaSameKey() throws Exception {
|
||||
StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(),
|
||||
Collections.emptySet());
|
||||
Method method = findMethod(Remote.class, "zap", boolean.class, String.class, String.class, String.class);
|
||||
|
||||
assertThatThrownBy(() -> {
|
||||
@@ -107,6 +117,8 @@ public class StandardParameterResolverTest {
|
||||
|
||||
@Test
|
||||
public void testTooMuchInput() throws Exception {
|
||||
StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(),
|
||||
Collections.emptySet());
|
||||
Method method = findMethod(Remote.class, "zap", boolean.class, String.class, String.class, String.class);
|
||||
|
||||
assertThatThrownBy(() -> {
|
||||
@@ -119,6 +131,8 @@ public class StandardParameterResolverTest {
|
||||
|
||||
@Test
|
||||
public void testIncompleteCommandResolution() throws Exception {
|
||||
StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(),
|
||||
Collections.emptySet());
|
||||
Method method = findMethod(Remote.class, "shutdown", Remote.Delay.class);
|
||||
|
||||
assertThatThrownBy(() -> {
|
||||
@@ -131,6 +145,8 @@ public class StandardParameterResolverTest {
|
||||
|
||||
@Test
|
||||
public void testIncompleteCommandResolutionBigArity() throws Exception {
|
||||
StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(),
|
||||
Collections.emptySet());
|
||||
Method method = findMethod(Remote.class, "add", List.class);
|
||||
|
||||
assertThatThrownBy(() -> {
|
||||
@@ -143,6 +159,8 @@ public class StandardParameterResolverTest {
|
||||
|
||||
@Test
|
||||
public void testUnresolvableArg() throws Exception {
|
||||
StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(),
|
||||
Collections.emptySet());
|
||||
Method method = findMethod(Remote.class, "zap", boolean.class, String.class, String.class, String.class);
|
||||
|
||||
assertThatThrownBy(() -> {
|
||||
@@ -157,6 +175,8 @@ public class StandardParameterResolverTest {
|
||||
|
||||
@Test
|
||||
public void testParameterKeyNotYetSetAppearsInProposals() {
|
||||
StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(),
|
||||
Collections.emptySet());
|
||||
Method method = findMethod(Remote.class, "zap", boolean.class, String.class, String.class, String.class);
|
||||
List<String> completions = resolver.complete(
|
||||
Utils.createMethodParameter(method, 1),
|
||||
@@ -172,6 +192,8 @@ public class StandardParameterResolverTest {
|
||||
|
||||
@Test
|
||||
public void testParameterKeyNotFullySpecified() {
|
||||
StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(),
|
||||
Collections.emptySet());
|
||||
Method method = findMethod(Remote.class, "zap", boolean.class, String.class, String.class, String.class);
|
||||
List<String> completions = resolver.complete(
|
||||
Utils.createMethodParameter(method, 1),
|
||||
@@ -187,6 +209,8 @@ public class StandardParameterResolverTest {
|
||||
|
||||
@Test
|
||||
public void testNoMoreAvailableParameters() {
|
||||
StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(),
|
||||
Collections.emptySet());
|
||||
Method method = findMethod(Remote.class, "zap", boolean.class, String.class, String.class, String.class);
|
||||
List<String> completions = resolver.complete(
|
||||
Utils.createMethodParameter(method, 2), // trying to complete --foo
|
||||
@@ -197,6 +221,8 @@ public class StandardParameterResolverTest {
|
||||
|
||||
@Test
|
||||
public void testNotTheRightTimeToCompleteThatParameter() {
|
||||
StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(),
|
||||
Collections.emptySet());
|
||||
Method method = findMethod(Remote.class, "shutdown", Remote.Delay.class);
|
||||
List<String> completions = resolver.complete(
|
||||
Utils.createMethodParameter(method, 0),
|
||||
@@ -207,8 +233,10 @@ public class StandardParameterResolverTest {
|
||||
|
||||
@Test
|
||||
public void testValueCompletionWithNonDefaultArity() {
|
||||
|
||||
resolver.setValueProviders(singletonList(new Remote.NumberValueProvider("12", "42", "7")));
|
||||
Set<ValueProvider> valueProviders = new HashSet<>();
|
||||
valueProviders.add(new Remote.NumberValueProvider("12", "42", "7"));
|
||||
StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(),
|
||||
valueProviders);
|
||||
|
||||
Method[] methods = {
|
||||
findMethod(org.springframework.shell.standard.Remote.class, "add", List.class),
|
||||
|
||||
Reference in New Issue
Block a user