i'm currently working on a little application with springBoot and got a configuration class like this :
#Configuration
public class ConfigurationExample {
#Value("${some.property}")
private String myProperty;
}
I'm not passing this value with the application.properties file but directly while launching the app
java -jar myApp.jar --some.property="Hello"
if i don't call the '--some.property="Hello"' it result on a big java error
I wanted to know if there is a way to catch this? In order to be able to print a clearer message
Thank you
The value binding happening at the run time(When Application start). If you forget pass then Application context initialization will fail.
This is application start issue
Better to use as below.
environment.gerProperty("key");
And add global exception handler and throw customized exception of value null.
if property does not exists and you still want to load application context
then you can do something like this
#Value("${some.property=: #{null}}")
private String some;
Related
I have a Spring Boot 2.7 Web/MVC server application with profiles for different environments (DEV/QA/PROD). I have a common application.properties with shared configuration and environment specific configuration, for example, JDBC URLs in separate application-<environment>.properties on the classpath.
If the application is started without a profile being selected, it fails with a cryptic error message complaining about a jdbcUrl property missing and not being able to initialize the context - all this within a huge stack trace. This is self-explanatory for the developer, but not trivial for an operations person.
What would be the Spring way of checking if exactly one profile is selected and displaying a non-stacktrace, human (operator) friendly error message?
I am looking for something similar to what is shown if the server port is already in use.
I would like to avoid hacks and find the Spring-endorsed solution for this.
it fails with a cryptic error message complaining about a jdbcUrl property missing and not being able to initialize the context - all this within a huge stack trace
The more fundamental problem seems to be that you're fighting the built-in Boot facilities that provide assistance to humans out of the box. Instead of using #Value("${jdbcUrl}") in your code, you should inject a javax.sql.DataSource, and Boot will automatically configure one when spring.datasource.url is set. If it's not present, you'll get an error that says "no bean of DataSource is available", and the auto-config report will explain why.
You can use a postprocessor for a value . If it is not present, then log your human friendly error error message and quit the application.
e.g
#Bean
public BeanPostProcessor bpp(Environment environment) {
return new BeanPostProcessor() {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(environment.getActiveProfiles()[0].equalsIgnoreCase(environment.getDefaultProfiles()[0])){
// Your Error message goes here
System.exit(1);
}
return bean;
}
};
}
I need to run some methods only once, when application starts for the first time. Is there any basic way to do this in Spring java/kotlin?
UPD:
For the first time means that i have new app that should run some methods on startup, but when i restart this app, i don't want it to run this method again
I would suggest that you use the ApplicationReadyEvent. According to the documentation, the ApplicationReadyEvent is an:
Event published as late as conceivably possible to indicate that the application is ready to service requests.
So, you could implement your own ApplicationListener listening for the ApplicationReadyEvent and run your code only when the application is ready, for example:
#Component
#Order(0)
class CustomApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
#Override
public void onApplicationEvent(ApplicationReadyEvent event) {
// run your code
}
}
You can annotate your method with #PostConstruct (make sure you've made spring bean).
At the beginning of that method you can check if file "dummy.txt" exists in project directory if not proceed with method. At the end create file "dummy.txt".
You can also add property while starting java process first time like this:
java -DfirstTime=true -jar myjar.jar
Make firstTime false by default
I have written a custom spring cloud stream sink application that starts up when I run it as a spring boot project in eclipse. When I deploy my application I need to pass in some system proeprties. See below.
#ComponentScan
#EnableConfigurationProperties(MyProperties.class)
#SpringBootApplication
public class MyApplication {//extends SpringBootServletInitializer{
public static final String COMPONENT_NAME = "my-application";
#Autowired
private MyProperties properties;
public static void main(String[] args) {
System.setProperty("server.env", "DEVT1");
System.setProperty("some.other.var", "foo");
SpringApplication.run(MyApplication.class, args);
}
I am trying to pass these system properties into dataflow using the Deployment Properties screen, picture below. I am wondering if I pass one of these if it is working. It seems like my application starts up but is looking for the other property. When I try passing both I get this weird error saying the main class can not be found. So when I pass one my application seems to get farther. Am I close to being on the right track? Do I need to separate the arguments some way? I tried with commas but it didn't seem to make a difference.
Error when passing two arguments -
Error: Could not find or load main class
LURzZXJ2ZXIuZW52PVBEMDYsLURBbWljYV9RdWV1ZV9NYW5hZ2Vycz1HV0QwNiwtRGNmZ21nci5jbGFzcy5wYXRoPVxhbWljYS5jb20MaWxlcxtudmNvbmZpZwdwcHJlc291cmNlcw==
So the picture in my post above is actually correct for setting jvm arguments. My error stemmed from one of my jvm arguments being a file path that was not exposed through docker. Make sure use-spring-application-json is unchecked if you specify your jvm args this way. So this is valid for passing jvm arguments...
through docker /res/ maps to a folder on my c drive.
Using a application.properties file my Spring Boot app can use some property values in it. A way to make sure a mandatory value must present is to add an annotation #Value for the property. The problem with this is the app fails miserably if the property value is not there in the properties file.
I am after a nicer less horrible way to say printing out a log line about "Property A is missing" instead of a whole stack trace. Is there a way to do this while still using #Value to initialise the properties? For example, property A is mandatory, an error is logged before app exits; property B is missing but not mandatory, a warning is logged and app continues.
If you can identify all property, then you can write a method in Application class with #Postconstruct, and inside your method, you can manually validate and log them
#Autowired
private Environment environment;
#PostConstruct
private void validateProperties() {
environment.getProperty(key);
.....
......
}
Alternatively, you can write your custom EnvironmentPostProcessor, and iterate all properties and log whichever is null/empty.
As you're using spring-boot consider creating a #ConfigurationProperties class rather than using the #Value annotation.
By doing that you can do your validations using Bean Validation, also in the same class, you can implement the interface InitializingBean and add extra validations/log messages as you with.
Follow this link on Spring's official docs to read more about #ConfigurationProperties.
I am debugging my Java Spring service and I get an #Autowired variable as null, when it shouldn't be.
Since I have declared the service's class as #Service, I want to double-check that my bean was scanned by Spring and included in the Application Context.
Therefore, I want to be able to observe in Eclipse the contents of the Application Context.
How is this possible?
inject ApplicationContext into a bean that you can debug and call #getBeanDefinitionNames
I am not sure if this is the best way but without adding any extra framework,if you just want to check if dependencies are injected correctly or not ,you can firstly remove #Autowired annotation from the fields.
Now create a parameterized constructor and annotate the constructor with #Autowired. Spring will try to inject all the beans through the constructor.
http://www.tutorialspoint.com/spring/spring_autowired_annotation.htm
Now you can put breakpoint inside the constructor to check what value is getting injected.
Hope this helps.
There is a workaround to get the WebApplicationContext in the debugger without changing the source code.
The RequestContextUtils#findWebApplicationContext method will help us with this.
You need to pass the current request to it, which can also be obtained using the static method:
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()
By combining these calls, you can get the context anywhere in the web application in the debugger and call any of its methods:
RequestContextUtils
.findWebApplicationContext(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest())
.getBeanDefinitionNames();
Slightly prettier version:
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
WebApplicationContext webApplicationContext = RequestContextUtils.findWebApplicationContext(request);
webApplicationContext.getBeanDefinitionNames();
you can use log4j.jar to output all the WARNINGS, DEBUGS, INFO once you start your server. Follow the below link http://www.tutorialspoint.com/spring/logging_with_log4j.htm. I have a working example at my other laptop, can post the code. Let me know if you need it