I have this application.properties:
url.up=${url:http://localhost:8080/upload}
And I want to extract the url "http://localhost:8080/upload". How can I extract it?
I tried something like this, but the url is null:
String url = config.getPropertyValue("url");
Where getPropertyValue:
public String getPropertyValue(String propertyKey) {
return properties.getProperty(propertyKey);
}
U can use #Value in your class
in your property file U can define
url.up=http://localhost:8080/upload
In Your class
#Value("${url.up}")
private String url;
then U can access the value using variable url
Unfortunately I do not know what class the config object is instatiated from which makes it hard to understand what the properties.getProperty() method call is doing. Therefore, I'll give you a a more general answer. As you are using Spring, you basically have two very elegant solutions to retrieve data from your application property files. If you just need a single value (as in your example the url.up field), then you would typically directly inject that value into the class that needs this data as in the following short Kotlin snippet (in java this would be very similar, just look up the #Value annotation on the internet).
#Component
class PropertyPrinter(
#Value("\${url.up}") private val url: String
) {
#PostConstruct
fun postConstruct() {
println("URL is: $url")
}
}
The other way would be to create a dedicated config class that hold a bunch logically connected fields and add the #ConfigurationProperties annotation. See here for a more in depth explanation.
You should use #Value annotation. For example:
#Value("${url}")
private String url;
The url variable holds http://localhost:8080/upload.
You should use #Value or appContext:
https://stackoverflow.com/a/29744955/21233858
Related
For example, let's say that in my yml file I had a variable called indicator. And based on what the indicator variable's value was I want the code to do something different. How would I access the yml variable in the regular code and use it accordingly?
You can use this:
#Value("${your.path.yml.string}")
private String x;
YML:
your:
path:
yml:
string: hello
x will be "hello"
You need to use Spring Expression Language which says we should write it as
#Value("${spring.application.name}")
private String appName;
For Default value if key is not present in yaml/yml or properties file
#Value("${spring.application.name: defaultValue}")
private String appName;
The last way you can fetch value is using environment object
#Autowired
private Environment environment;
String appName = environment.get("spring.application.name");
You can add #Value annotation to any field in your beans.
#Value("$(path.to.your.variable)")
String myString;
Works with constructors as well.
public MyClass(#Value("$(path.to.your.variable)") String myString) {
You can use #Value on fields or parameters to assign the property to some variable.
Property example:
#Value("${indicator}")
private String indicator
Parameter example:
private void someMethod(#Value("${indicator}") String indicator) {
...
}
Then you can use indicator as you want.
Note: the class where you use #Value should be a Spring Component
With Spring-Boot, you have the file application.yml automatically provided for you. What you can do is adding a property in this file, for instance:
my.properties: someValue
Then, in one of your Spring Bean (either define with #Component or #Bean) you can retrieve this value using the annotation #Value. Then, do whatever you want with this variable.
For instance:
#Component
public class MyClass {
#Value("${my.properties"}
private String myProp; // will get "someValue" injected.
...
// Just use it in a method
public boolean myMethod() {
if(myProp.equals("someValue") {
// do something
} else {
// do something else
}
}
}
The best way to do this is not to have a tight coupling between Spring and your "normal" code at all, but instead to use the normal Java features like constructors along with Spring #Bean methods:
class MyService {
final String indicatorName;
MyService(String indicatorName) {
this.indicatorName = indicatorName;
}
}
... in your configuration class...
#Bean
MyService myService(#Value("indicator.name") String indicatorName) {
return new MyService(indicatorName);
}
Two notes for Spring Boot specifically:
The #ConfigurationProperties feature allows you to map properties onto structured Java data classes and is typically cleaner than using #Value by hand.
Always namespace properties that you define yourself to avoid future collisions with other libraries, so instead of indicator.name use company.project.indicator.name. I recommend looking at DataSourceProperties in Boot to see an example of how to set all this up.
More broadly, though, when you say that you want the code to "do something different", it sounds like the better option might be to have different classes that get activated under different circumstances. Both Spring profiles and Spring Boot auto-configuration help to do this.
The problem statement can be re-defined as Configuration Management in Java.
You should have a component like ConfigManager that gets instantiated as part of your application start up. That component will read a properties file, a yaml in your use case. Subsequent app logic will fetch these values from the ConfigManager exposed as simple key/value pairs.
All that is left for you to identify how to read and parse values from yaml file. This is already answered here:
Parse a YAML file
I've been blown away by something and my sleep is nowhere after finding out that my code is working from last 2 years when clearly it shouldn't!
So it's a Spring boot application. The application has some controllers. One of the classes I'm using extends WebServiceGatewaySupport, so requires that I #Autowire this. The class name is AClient. Now, this class needs 4 properties to work. Three of them are coming from properties file, e.g.
#Value("${a.userName}")String userName;
So three properties are obviously picked from application.properties file. Now the fourth property had me blown away. It is NOT being fetched as rest three, but is being copied from constructor parameter. So we have only one constructor in the class:
public AClient(String d){
this.d=d;
}
Now this property is being used in one of the methods this class has
public String getSomeData(){
// This method gets Data based on property d
}
And interestingly and surprisingly, this property's value is present everytime this bean is accessed! The bean is #Autowired at one place only, inside the Controller class. I haven't marked the property value to be fetched from application.properties file. I haven't provided this class any clue where to get the value of d from. I haven't provided any public methods for other classes to set this value. Yet the code is working and I can even place a debug pointer in method getSomeData() and see that the value of d is present!
Now I understand I might be missing something obvious, but what? Is there a way I can get into Spring container when #Autowired objects are being instantiated and debug from that point to see where this value is coming from? I've checked the code multiple times. Run hundreds of query on Google to find something like Spring boot does some magic stuff to map the missing String properties. But the variable name in properties file is different from what it is in AClient class. So how can it even map? This is truly killing me now!
Addition:
Less relevant, but the code is being accessed in a standard way:
#Autowired
AClient aClient;
public someOtherMethod(){
aClient.getSomeData();
}
So when I place a debugger on first line of someOtherMethod() and hover over aClient, it shows variable d value populated, same as in application.properties file!
Edit:Here's what I missed:
#Configuration
public class someConfig{
#Bean
public AClient aClient(){
// Someone else fetched property from application.properties file, created an object of AClient class using argument constructor and returned that object here. So now Spring is using #Autowire reference for this object I guess
}
}
So basically, your #Configuration class looks similar to this?
#Configuration
public class SomeConfig {
#Value("${a-client.important-value-d}")
private String importantValueDFromApplicationProperties;
#Bean
public AClient aClient() {
return new AClient(importantValueDFromApplicationProperties);
}
}
If yes, then Spring will the aClient for every #Autowired requesting it. Therefore the value of importantValueDFromApplicationProperties will be present in this certain instance.
Another note:
I would recommend using Spring Boot's #ConfigurationProperties instead of #Value. Take a look.
I have below code and issue. I am running a Spring boot application to test application.properties file usage.
application.properties file,
server.port=8080
server.servlet.context-path=/HelloWorldBoot
myMap={key1:'value1',key2:'value2'}
Controller code below,
#RestController
public class MyController {
#Autowired
Environment env;
#Value("#{${myMap}}")
private HashMap<String,String> myMapUsingValue;
#GetMapping("/hello")
public String hello() {
System.out.println("myMapUsingValue : "+myMapUsingValue);
HashMap<String, String> myMapUsingEnv = env.getProperty("myMap", HashMap.class);
System.out.println("myMapUsingEnv : "+myMapUsingEnv);
return "Hello World";
}
}
Now when I hit the URL: http://localhost:8080/HelloWorldBoot/hello
Map details using #Value gets printed successfully,
myMapUsingValue : {key1=value1, key2=value2}
But I get error like below while accessing the same Map using Environment API,
No converter found capable of converting from type [java.lang.String] to type [java.util.HashMap<?, ?>]]
How can I resolve this? How can I read the Map directly from application properties file using the Environment variable API?
Any help is appreciated on this. Thanks in advance.
Environment variables are always strings. The fact that the Spring value injector knows how to convert them to a map is super nice, but when using the java environment api you are going to have to parse that string yourself and convert it into a Map.
Something like Jackson might make this easier. Otherwise you might write a utility method that does this. You might look in the spring source.
Don't think too much just check your pojo class.
Getting value from database is different , field from pojo class is different.
in my project it's necessary to inject a value from the application.properties file, profile-dependent, into the endpoint-class to the namespace-variable of the #PayloadRoot annotation.
The problem: the namespace-value must be a constant and in spring I can't inject a value into a final variable.
I find an advice to inject in this way:
#PayloadRoot(namespace = "${my.namespace}", localPart = "getMyRequest")
#ResponsePayload
public JAXBElement<MyResult> myMethod(#RequestPayload JAXBElement<MyInput> request) {
but ... it doesn't work.
Has anyone a working solution?
Thanks...
You could do one of the following:
1) Use reflection once you have the appropriate value (but you need to make sure that you set the value before the endpoint mapping occurs): example here
2) Extends the class PayloadRootAnnotationMethodEndpointMapping and in the method getLookupKeysForMethod, use a custom a method getQNameFromAnnotation where you will inject the correct value of the namespace.
private QName getQNameFromAnnotation(PayloadRoot payloadRoot) {
return new QName(/*INJECT YOURNAMESPACE HERE*/, payloadRoot.localPart());
}
I need to use a response from a rest service returning JSON. However, one of the fields in the json response is the empty string. So, basically this:
{"wut":
{
"foo":"fooval",
"": "srsly"
}
}
So, I need to somehow translate this into a java class, as below:
#JsonIgnoreProperties(ignoreUnknown=true)
public class wut
{
#JsonProperty
private String foo;
#JsonProperty
private String <empty string???>;
//etc...
}
As you might expect, I don't have enough control over the endpoint to be able to give the property a name. Is there a way to handle this?
I'm using RestTemplate from spring to make the call, if that matters at all.