I already managed to start Spring Shell using Spring Boot:
#SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class);
}
}
All my #ShellComponent classes are detected and I can use the shell as expected.
Now I would like to run the shell without Spring Boot, I expect it to look something like this
Shell shell = context.getBean(Shell.class);
shell.run(...);
What approach should I take to configure all required dependencies myself?
Thanks in advance!
By extracting the necessary parts of ebottard's link (Thank you!) I finally managed to run the shell like I wanted:
#Configuration
#Import({
SpringShellAutoConfiguration.class,
JLineShellAutoConfiguration.class,
JCommanderParameterResolverAutoConfiguration.class,
StandardAPIAutoConfiguration.class,
StandardCommandsAutoConfiguration.class,
})
public class SpringShell {
public static void main(String[] args) throws IOException {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringShell.class);
Shell shell = context.getBean(Shell.class);
shell.run(context.getBean(InputProvider.class));
}
#Bean
#Autowired
public InputProvider inputProvider(LineReader lineReader, PromptProvider promptProvider) {
return new InteractiveShellApplicationRunner.JLineInputProvider(lineReader, promptProvider);
}
}
See this example that shows how to wire up everything without relying on Autoconfiguration.
without Spring Boot I write this:
#Configuration
#ComponentScan(value = {"path.to.commands", "org.springframework.shell.commands", "org.springframework.shell.converters", "org.springframework.shell.plugin.support"})
public class TestShell {
private static String[] args;
#Bean("commandLine")
public CommandLine getCommandLine() throws IOException {
return SimpleShellCommandLineOptions.parseCommandLine(args);
}
#Bean("shell")
public JLineShellComponent getShell() {
return new JLineShellComponent();
}
public static void main(String[] args) {
TestShell.args = args;
System.setProperty("jline.terminal", "none");
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(TestShell.class);
ctx.registerShutdownHook();
JLineShellComponent shell = ctx.getBean(JLineShellComponent.class);
shell.start();
shell.waitForComplete();
ExitShellRequest exitShellRequest = shell.getExitShellRequest();
if (exitShellRequest == null)
exitShellRequest = ExitShellRequest.NORMAL_EXIT;
System.exit(exitShellRequest.getExitCode());
}
}
and command class:
#Component
public class Hello implements CommandMarker {
#CliCommand(value="hi", help = "say hello.")
public String hi() {
return "hello";
}
}
see org.springframework.shell.Bootstrap.
Related
I have the below code when i put some properties statically in SpringApplicationBuilder
#SpringBootApplication(scanBasePackages = { "com" })
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplicationBuilder parentBuilder = new SpringApplicationBuilder(Application.class);
parentBuilder.child(RestConfiguration.class, SwaggerConfig.class)
.properties("server.port:9093")).web(WebApplicationType.SERVLET).run(args);
}
}
I want to move the properties to the file application.properties
application.port.query=9093
I used #value to read from the application file, but i get null. Is there another way to read data in a static method?
try something like this
#Configuration
#ConfigurationProperties("application")
class A {
public static int queryPort;
#Value("${port.query:9093}")
public void setQueryPort(final int portQuery){
A.queryPort = portQuery;
}
}
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplicationBuilder parentBuilder = new SpringApplicationBuilder(Application.class);
parentBuilder.child(RestConfiguration.class, SwaggerConfig.class)
.properties(A.queryPort)).web(WebApplicationType.SERVLET).run(args);
}
}
The preferable way to what you are trying to achieve is to use the spring bean itself which is the parent of your all configurations org.springframework.core.env.Environment
#SpringBootApplication(scanBasePackages = {"com"})
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext =
SpringApplication.run(Application.class, args);
Environment environment = applicationContext.getBean(Environment.class);
String propertyValue = environment.getProperty("any.property.from.configuration")
}
}
In your use-case, just get the bean of Environment and from Environment object get any property value.
Application.java
#SpringBootApplication(scanBasePackages = {"ru.pcask.clients",
"ru.pcask.activities"
})
#EntityScan(value={"ru.pcask.clients",
"ru.pcask.activities"})
#EnableJpaRepositories(value={"ru.pcask.clients",
"ru.pcask.activities"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
"ru.pcask.clients" seems to be a constant. But I don't know how to organize it?
I tried like this:
Constants.java
#Configuration
public class Constants {
private static final String CLIENT = "ru.pcask.clients";
#Bean
public String getClientConst() {
return this.CLIENT;
}
}
But this seems to be a garbage. I don't even know how to use it in #SpringBootApplication.
I have SpringBootApplication that takes args
public class RocksdbBootApp {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(RocksdbBootApp.class);
app.setDefaultProperties(Collections.singletonMap("server.port", args[0]));
app.run(args);
}
}
How can I get access to args in RestController?
#Slf4j
#RestController
#RequestMapping("/api/rocks")
public class RocksApi {
public RocksApi(KeyValueRepository<String, String> rocksDB) {
System.out.println(args[0]);
}
}
To access arguments passed to your application you can make use of ApplicationArguments and inject it into your controller :
#Slf4j
#RestController
#RequestMapping("/api/rocks")
public class RocksApi {
private final ApplicationArguments arguments;
#Autowired //can be ommited in new versions of Spring
public RocksApi(final ApplicationArguments arguments) {
this.arguments = arguments;
}
public RocksApi(KeyValueRepository<String, String> rocksDB) {
String[] args = arguments.getSourceArgs();
System.out.println(args[0]);
}
}
afaik, you're setting an application property, and can acccess that like any other Spring property:
#Slf4j
#RestController
#RequestMapping("/api/rocks")
public class RocksApi {
#Value("${server.port}")
private Integer serverPort;
I'm building a Spring Boot application and need to read command line argument within method annotated with #Bean. See sample code:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public SomeService getSomeService() throws IOException {
return new SomeService(commandLineArgument);
}
}
How can I solve my issue?
#Bean
public SomeService getSomeService(
#Value("${cmdLineArgument}") String argumentValue) {
return new SomeService(argumentValue);
}
To execute use java -jar myCode.jar --cmdLineArgument=helloWorldValue
You can also inject ApplicationArguments directly to your bean definition method and access command line arguments from it:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public SomeService getSomeService(ApplicationArguments arguments) throws IOException {
String commandLineArgument = arguments.getSourceArgs()[0]; //access the arguments, perform the validation
return new SomeService(commandLineArgument);
}
}
try
#Bean
public SomeService getSomeService(#Value("${property.key}") String key) throws IOException {
return new SomeService(key);
}
If you run your app like this:
$ java -jar -Dmyproperty=blabla myapp.jar
or
$ gradle bootRun -Dmyproperty=blabla
Then you can access this way:
#Bean
public SomeService getSomeService() throws IOException {
return new SomeService(System.getProperty("myproperty"));
}
you can run your app like this:
$ java -server -Dmyproperty=blabla -jar myapp.jar
and can access the value of this system property in the code.
If I am developing a rather simple Spring Boot console-based application, I am unsure about the placement of the main execution code. Should I place it in the public static void main(String[] args) method, or have the main application class implement the CommandLineRunner interface and place the code in the run(String... args) method?
I will use an example as the context. Say I have the following [rudimentary] application (coded to interfaces, Spring style):
Application.java
public class Application {
#Autowired
private GreeterService greeterService;
public static void main(String[] args) {
// ******
// *** Where do I place the following line of code
// *** in a Spring Boot version of this application?
// ******
System.out.println(greeterService.greet(args));
}
}
GreeterService.java (interface)
public interface GreeterService {
String greet(String[] tokens);
}
GreeterServiceImpl.java (implementation class)
#Service
public class GreeterServiceImpl implements GreeterService {
public String greet(String[] tokens) {
String defaultMessage = "hello world";
if (args == null || args.length == 0) {
return defaultMessage;
}
StringBuilder message = new StringBuilder();
for (String token : tokens) {
if (token == null) continue;
message.append(token).append('-');
}
return message.length() > 0 ? message.toString() : defaultMessage;
}
}
The equivalent Spring Boot version of Application.java would be something along the lines:
GreeterServiceImpl.java (implementation class)
#EnableAutoConfiguration
public class Application
// *** Should I bother to implement this interface for this simple app?
implements CommandLineRunner {
#Autowired
private GreeterService greeterService;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
System.out.println(greeterService.greet(args)); // here?
}
// Only if I implement the CommandLineRunner interface...
public void run(String... args) throws Exception {
System.out.println(greeterService.greet(args)); // or here?
}
}
You should have a standard loader:
#SpringBootApplication
public class MyDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MyDemoApplication.class, args);
}
}
and implement a CommandLineRunner interface with #Component annotation
#Component
public class MyRunner implements CommandLineRunner {
#Override
public void run(String... args) throws Exception {
}
}
#EnableAutoConfiguration will do the usual SpringBoot magic.
UPDATE:
As #jeton suggests the latest Springboot implements a straight:
spring.main.web-application-type=none
spring.main.banner-mode=off
See docs at 72.2