Assign a property value in a Java class-level annotation - java

In my application.properties, I have a property as this:
myAppContext=something.special
The Spring app reads the properties from this file.
I want to access the above property in a class-level annotation as this:
// "contexts" take in an array of string values
#AClassLevelAnnotation(contexts = {"something.special"})
public class Amazing{}
Instead of using the value (which already exists in the properties file) I would like to access it using the property key, something like this, which does not work:
#AClassLevelAnnotation(contexts = {#Value("${myAppContext}")})
public class Amazing{}
Any suggestion on how this can work?

Try making a bean:
#Bean
public static PropertySourcesPlaceholderConfigurer getPropertyConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Using #Óscar López's suggestion: contexts = "${myAppContext}" That syntax should be working, especially if the property value is a string.
Try this without the brackets first. If you need an array, you may want to consider using a comma-separated value in your application.properties, or even something like contexts = "#{Arrays.asList(\"${theProperty}\")}", with the comma-separated value, if you need a different Collection type.

Related

How to define empty list in application.yml in spring boot

I've got application.yml in my spring boot project and want to declare empty list. I mean there is a two level config hierarchy. This class is required to get values declared in application.yml
#Configuration
#ConfigurationProperties("book")
public class PropertiesReader {
private List<Long> authors;
public List<Long> getAuthors() {
return new ArrayList<>(authors);
}
public void setAuthors(List<Long> authors) {
this.authors= new ArrayList<>(authors);
}
And this is how part of application.yml looks like
book:
library: ${LIBRARY_REFERENCE:library}
secondValue:
expirationAfter: 10
authors: ${AUTHORS_IDS:[]}
So values in curly brackets are declared in another, external configuration file. But if value isn't there declared, spring should assign default value that is declared after colon symbol. In single values it works, but in List if I declare it as above I'm getting NumberFormatException because value [] is assigned to list. How to write it properly?
In external configuration how should it be written also? If I want sometimes to declare values but sometimes it must be empty
name: AUTHORS_IDS
value:
You only need to put a colon sign. I have solved my problem like that, it works.
book:
authors: ${AUTHORS_IDS:}

How to read application.properties value inside the constructor in spring boot?

I know Constructors are calling before the auto wiring the variables. But, unfortunately, I want to read the application.properties value inside the constructor?
#Component
public class DESedeEncryption {
private static final String key = "TEST_KEY";
public DESedeEncryption() {
system.out.println(key);
}
}
DESedeEncryption encrypted = new DESedeEncryption();
For the above class, the object has been created by using a new operator in my project totally 108 places. Now, I want to read that key value from the application.properties. But, I need to change all 108 places by using #Autowired annotation. But, some of the places the object creation written by using "new" operator in entity class files. So, I can't auto wired the object inside the entity class.
Someone, please help me to solve this issue.
You can declare a variable inside the Constructor with #Value annotation, where you want call the application.properties variable.
Example class:
public DESedeEncryption(#Value("${key}") final String key) {
system.out.println(key);
}

Central configuration file with Spring

I am building a software system using Java 11 with SpringBoot 2.1. I am thinking about configuration options yet all ways of implementing configuration in Spring I found so far go in other directions. So here is what I want/need:
First, I will have some hardcoded configuration values. They shouldn't be adaptable via a configuration file that is loaded during runtime.
Example: Application name.
Second, I want an (internal) properties file for configuration values. These would (mostly) only be edited by developers and would hence serve as standard values when starting the application.
Example: application version.
Finally, there will be some configuration values that should be editable by the user during runtime using some UI.
Example: Application port
Now, I would like to have a central configuration file, think Singleton pattern, that manages configuration values from all three categories listed above. The idea is that I can access all that from everywhere in the application easily.
Ideally, I'd have a singleton class with a central function taking a config parameter and returning the respective value.
class MyConfig {
private static singleton = null;
private MyConfig() {}
// needed: some name-value storage management for params
// e.g.: some hardcoded values plus one or more linked property files.
public static String getProperty(String paramName)
// fetch parameter and return it
}
public static String getProperty(String paramName, String returnType)
// fetch parameter and return it cast to the specified returnType
}
public static String setProperty(String paramName, String value)
// persist property value to file
}
}
When starting the application, the configuration should basically do
Load hardcoded values into config object (if not specified in config class itself)
Load values from property file.
Values loaded must be checked for validity (e.g. is app_port an integer [1, 65535]).
Values from property file must be pre-registered, so a user with write access to the property file cannot "add" a made up new config parameter by adding it.
Values from property file must not overwrite hardcoded values.
When the user edits the configuration during runtime, the respective values need to be written back to the properties file (or where-ever they are stored)
Unfortunately, I didn't find anything like this out there and I don't know how to get Java Properties and/or Spring Properties/Configurations to implement something like this.
Anyone, who can point me in the right direction or provide a minimal working example?
You can load your properties from properties file in MyConfig class constructor into Immutable Map. Make this Immutable Map your class level attribute so that you can access all the properties using this attribute.
class MyConfig {
public static Map<String, String> immutableMap = null;
private MyConfig() {
Map<String,String> modifieableMap = new HashMap<>();
//code to load properties into modifieableMap
immutableMap = ImmutableMap.copyOf(mutableMap);
}
// needed: some name-value storage management for params
// e.g.: some hardcoded values plus one or more linked property files.
public static String getProperty(String paramName)
// fetch parameter and return it
}
public static String getProperty(String paramName, String returnType)
// fetch parameter and return it cast to the specified returnType
}
public static String setProperty(String paramName, String value)
// persist property value to file
}
}
If user tries to add or remove any property from Immutable Map, the compiler will throw UnsupportedOperationException exception

Passing a variable to #Value annotation for reading specific property from properties file

In my Spring boot application, a specific value needs to be read from the properties file depending on a string value returned from another function. My properties file is as follows:
A=value_a
B=value_b
A function returns either A or B, and stores it in a String variable called stringValue . I am looking for doing something along the lines of the following:
#Value(stringValue)
String propertyValue
However, I get the following message on my IDE:
Attribute value must be constant
I have tried to convert stringValue to a static final variable, but to no avail.
I do know that I can pass a specific key to be read from the properties file, such as the following:
#Value("${A}")
String valueOfA
My question is whether I can pass a variable to the #Value annotation?
#Value annotations are resolved during startup, when Spring context is built. Since stringValue would not be available at this time, you can't use it for injection purposes.
An exception to this scenario would be if the bean with #Value annotation is prototype-scoped, in which case a new instance of it would be created any time it's requested. Still, stringValue would need to be available to the Spring context in order to be used at injection point.
Without seeing more code, it's not possible to give you any more detailed answer.
You can autowire Environment in your application and use it to read from the properties file as it is supposed to be at runtime.( This is assuming all files where your properties are have been added to environment).
I will be posting my answer with assumptions as you have not updated your question, with all information I requested.
So your code would be-
lets call your class where your making a call to a function called getValue to get value of stringValue- Example. Now lets assume you are making a call to the function getValue in a method in the class Example called doSomething().
class Example{
#Autowire
private Enviornment environment.
private String propertyValue
public void doSomething(){
String value=getValue()// this is where u know whether
its A or B.
propertyValue=environment.getProperty(value);
// do whatever u want know
}
Thanks for the help guys! I read the values from the properties file into a org.springframework.core.io.Resource object, and then used that to retrieve the specific value that I required. The following was how I structured my solution code:
#Value("classpath:config.properties")
private Resource propertiesfile;
I then declared a java.util.Properties object and read the values from the Resource object into it.
Properties properties = new Properties();
try{
properties.load(propertiesfile.getInputStream());
}catch(IOException e){
logger.error("Parsing error while reading properties file",e.toString());
}
Finally, based on the value in my stringValue variable, I read the corresponding value from the properties file
String propertyValue = properties.getProperty(stringValue);
if your variable is another environment variable you can try in this format.
#Value("${${stringvalue}}")
where stringvalue is the environment variable.

Spring #Value from .properties file null in debug eclipse

The purpose of my code is to load some settings value from a *.properties file so that I later can use these values in some if-statements in my code. I want to load in some list-structure, but since that seems hard, an array will do. I have not really gotten that far, since I am stuck at the trivial matter of loading just a String from the properties file.
When I try to debug my code that is using some spring specific data. I get some interesting behaviour, pointing on the definition in the code right above the breakpoint gives me that the variable value is null.
#Value(value = "${ViewableReportFilter.allStates.verify}")
String verifyStringStates;
public ViewableReportFilter() {
viewStates = null;
log.debug("Read in properties for states: verify:" + verifyStringStates);
/*BREAKPOINT HERE*/
in my my.properties file:
ViewableReportFilter.allStates.verify=ONHOLD
And my config to use the properties-file:
<context:property-placeholder location="classpath:properties/my.properties" order="1" ignore-unresolvable="true" />
Spring can't set the fields of an object before that object is created. The first thing Spring does is use reflection to instantiate your class. It'll use either Class#newInstance() or use Constructor#newInstance() depending on the context. Only when the constructor has finished its work and returned can Spring, again using reflection, set the value of fields.
An alternative is to put a #Value annotated parameter in the constructor parameter list and set your field inside your constructor from the argument that's given to it by Spring.
public ViewableReportFilter(#Value String verify) {
this.verifyStringStates = verify;
...
Go through the Spring documentation for its IoC container. It explains all of this in much detail.
Updated the constructor, and added Autowire annotation. No changes in the properties file, no XML.
String arrayOfStrings;
#Autowired
public ViewableReportFilter(
#Value("${TMSViewableReportFilter.allStates.verify}") String[] verifyStringStates) {
arrayOfStrings = verifyStringStates;
public logViewableReportFilter() {
log.debug("Read in properties for states: verify:" + arrayOfString);
}
Try using this:
#Value(value = "${allStates.verify}")
And in your property my.properties:
allStates.verify=ONHOLD

Categories