Spring boot arguments from comand line - java

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;

Related

#ConstructorBinding seems not to work in Spring Boot 2.5.4

I'm using Spring Boot 2.5.4 and am trying to initialize an immutable class from properties:
#Configuration
#ConfigurationProperties("test")
public class Config {
public final String foo;
#ConstructorBinding
public Config(String foo) {
this.foo = foo;
}
}
application.yml:
test:
foo: bar
Main class:
#SpringBootApplication
#ConfigurationPropertiesScan
public class Application implements CommandLineRunner {
#Autowired Config config;
public Application(Config config) {
this.config = config;
}
public static void main(String[] args) { SpringApplication.run(Application.class, args); }
#Override
public void run(String... args) {
System.out.println(config.foo);
}
}
I would expect this to start and print "bar". However, it fails to start with
Parameter 0 of constructor in Config required a bean of type 'java.lang.String' that could not be found.
When I remove the #ConstructorBinding and add a setter and nullary constructor, it does work.
Add #ConstructorBinding in class level. And remove #Configuration annotation. Like this,
#ConstructorBinding
#ConfigurationProperties("test")
public class Config {
public final String foo;
public Config(String foo) {
this.foo = foo;
}
}

Run Spring Shell 2 without Spring Boot

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.

How to invoke repository method for standalone application?

I have following repository which extends jpa repositroy and also have an implementation class where i have autowired this.
#Repository
public interface ProjectDAO extends CrudRepository<Project, Integer> {}
#Service
public class ProjectServiceImpl {
#Autowired private ProjectDAO pDAO;
public void save(Project p) { pDAO.save(p); } }
Now i have one Application.java class
Class Application{
public static void main(String..s){
// I need a way to call a method of repository
}
}
configuration file
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories
#PropertySource("file:/Users/abc/Documents/application.properties")
public class PersistenceContext {
#Autowired
Environment environment;
So how do we call this from main in case i dont to use any web based controller?
This is a way:
class Application {
public static void main(String[] s){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(PersistenceContext.class);
ProjectDAO dao = applicationContext.getBean(ProjectDAO.class);
}
}
Edit:
class Application {
public static void main(String[] s){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(PersistenceContext.class);
ProjectServiceImpl service = applicationContext.getBean(ProjectServiceImpl.class);
}
}

Error creating bean with name 'application', No default constructor found; nested exception is java.lang.NoSuchMethodException

I don't quite understand why this code gives me 'no default constructor found' error. The constructor is #Autowired. Everything seems to be injected correctly. Can anybody please help? Thanks
#SpringBootApplication
public class Application {
private ApplicationContext applicationContext;
private MessagingService messagingService;
private Parser parser;
private static final Logger log = LoggerFactory.getLogger(Application.class);
#Autowired
public Application(ApplicationContext applicationContext,
MessagingService messagingService,
Parser parser)
{
this.applicationContext = applicationContext;
Assert.notNull(messagingService, "MessagingService must not be null");
this.messagingService = messagingService;
Assert.notNull(parser, "Parser must not be null");
this.parser = parser;
}
public static void main (String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner app() {
return args -> {
Locale defaultLocale = Locale.getDefault();
Locale.setDefault(defaultLocale);
log.info("Using MessagingService: " + messagingService.getMyMessageCode());
parser.parse();
};
}
}
Edit: updated Application.class
#SpringBootApplication
public class Application {
#Autowired
private MessagingService messagingService;
#Autowired
private Parser parser;
private static final Logger log = LoggerFactory.getLogger(Application.class);
public Application() {}
public static void main (String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner app() {
return args -> {
Locale defaultLocale = Locale.getDefault();
Locale.setDefault(defaultLocale);
log.info("Using MessagingService: " + messagingService.getMyMessageCode());
parser.parse();
};
}
}
Answer from luboskrnac is correct.
But if you really want to use Constructor Injection you can upgrade you SpringBoot version to 1.4.0.RELEASE which will use Spring 4.3.2.RELEASE
From Spring 4.3 Constructor Injection is supported on #Configuration class
New Features and Enhancements in Spring Framework 4.3
You can't autowire into main Spring Boot class. You can inject dependencies needed for CommandLineRunner as parameters of method annotated with #Bean and of course remove constructor injection for main class:
#SpringBootApplication
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
public static void main (String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner app(ApplicationContext applicationContext,
MessagingService messagingService,
Parser parser) {
return args -> {
Locale defaultLocale = Locale.getDefault();
Locale.setDefault(defaultLocale);
log.info("Using MessagingService: " + messagingService.getMyMessageCode());
parser.parse();
};
}
}
EDIT:
Correct context configuration after edit:
#SpringBootApplication
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
public Application() {}
public static void main (String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner app(MessagingService messagingService, Parser parser) {
return args -> {
Locale defaultLocale = Locale.getDefault();
Locale.setDefault(defaultLocale);
log.info("Using MessagingService: " + messagingService.getMyMessageCode());
parser.parse();
};
}
}

#Autowired fails in spring boot web project

I have a simple Spring Boot web project, right from a template:
#SpringBootApplication
#RestController
public class HelloWorldRestApplication {
public static void main(String[] args) {
SpringApplication.run(HelloWorldRestApplication.class, args);
Performer p = new Performer();
p.perform();
}
}
I have a test to ensure autowiring works, and in fact it does in this test class (examples come from Spring in Action, 4th):
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=CDPlayerConfig.class)
public class CDPlayerTest {
#Autowired
private CDPlayer cdp;
#Test
public void cdShouldNotBeNull(){
assertNotNull(cdp);
}
}
and:
public class Performer {
#Autowired
private CDPlayer cdp;
public void perform(){
System.out.println(cdp);
cdp.play();
}
public CDPlayer getCdp() {
return cdp;
}
public void setCdp(CDPlayer cdp) {
this.cdp = cdp;
}
}
and:
#Component
public class CDPlayer{
public void play(){
System.out.println("play");
}
}
config:
#Configuration
#ComponentScan
public class CDPlayerConfig {
}
However, it doesnt work in HelloWorldRestApplication, I get null.
Adding #ContextConfiguration(classes=CDPlayerConfig.class) doesn't help.
What do I miss?
Try enabling #ComponentScan your packages in your main class and get Performer class instance from ApplicationContext as below:
#SpringBootApplication
#RestController
#ComponentScan({“package.name.1”,”package.name.2”})
public class HelloWorldRestApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(HelloWorldRestApplication.class, args);
Performer p = ctx.getBean(Performer.class);//get the bean by type
p.perform();
}
}

Categories

Resources