Property #value Spring - java

In spring, we can use #value annotation to refer a property value that is defined in the property file. In this approach, the way it would be something like
To have a separate property file and define the property name and value
To list this property class path in a spring config file
Finally referring the value in a class with #value annotations as
#value("{key_name}") String abc;
Other hand , we can try simply define that property value as a constant in the class something like the below and use it in the class.
public static final String key_name = "1q2w3e";
Since we have this simple approach, why we are using #value annotation approach as defined above.
Please help me to understand in detailed about it.

Using configuration values from external sources (e.g. property files) has many advantages. Some of them:
You can change the configuration without recompiling your code.
You can have multiple instances of the same binary-code running with different configuration values.
Configuration values can not only come from property-files that are bundled with your application, but from different sources like system-properties, environment-values, a database or any other custom source.
As a general rule only use constant values for things that will never change like the value of PI.

There's a big disadvantage in using the second method. Think of a scenario where you changed the language. If you were relying on the first approach you'd have to go through each class and change the value assigned to key_name. Now, if you were using the second method you'd only have to change the value assigned to key_name in one place, and that's in the properties file which is much simpler and make things more manageable.

Related

How to prevent Spring from performing variable replacement

I have a configuration property that needs to be sent to another system as part of a post body.
lets say for example if have an application.properties file with
my.property.raw=${parameter:some-identifier}
I also have a #ConfigurationProperties annotated class that might look like this
#ConfigurationProperties(prefix = "my.property")
public class Properties {
private String raw;
// getters and such
}
The problem i have is that Spring will see ${parameter:some-identifier} and immediately assumes i want it to be injected with a property names "parameter" and if its not there, put "some-identifier". i have tried to set the property to ${parameter:${parameter:some-identifier}} but Spring seems to have accounted for recursive property injection and it still comes out as "some-identifier".
I know i can write some code around that and replace the ":" with something else and change it back after the fact but i'm trying to make this work without any code change.
So in summation, Spring boot sees this as a configuration property ${parameter:some-identifier} upon injection into the ConfigurationProperties annotated class, the value ends up being some-identifier. What i want to happen is the value in the Properties class after Spring does its variable replacement process is ${parameter:some-identifier} as this injectable format of a value is intended for a down stream system that is expecting that format. Preferably, without changing any code. Maybe there is some special formatting i can use to tell spring to ignore this specific property.
Thanks for your time! and yes i realize this is probably the opposite of what people normally want from Spring.
As stated by #Kayaman this is indeed a duplicate of
Escape property reference in Spring property file
The solution i pulled from there, with some modification, was this:
${dollar:$}{parameter:some-identifier}
https://stackoverflow.com/a/48897422/4621716
I did this because i also don't have control over the process that is generating that application.properties beyond changing existing values.
I hope this helps and i wish i could give #Kayaman credit for pointing me in the right direction but i guess i'll accept my own answer. Thanks.

guice multiple bindings for a single constant

I have a java app that uses guice to do configuration.. I dont think this is what it is intended for but its what has been done and I only need to make a small change so I would prefer not to remove guice.
Basically, java properties are bound to variables, I want to bind some to an environmental variables or to a java property.
This is what I currently have
bindConstant().annotatedWith(Names.named("value")).to(properties.getProperty("java.property.value"));
this is what I would like to do
bindConstant().annotatedWith(Names.named("value")).to(System.getenv("JAVA_PROPERTY_VALUE"));
Is there a way to combine the two? I cannot do both. Or, is this just a default and I basically have what I need already? ie if I do bindConstant to System.getenv that value will be used unless its overwritten in the properties file (in my case the string constant is not the full property name so I am unsure how it works now).
I really do not know much about how guice works, I believe an injector is created where this code is and later used to do things like...
#Inject(optional = true)
#Named("value)
private String value;
I basically want that value to default to the one in the properties file, but be overridden by the env property value if its present.
I have tried simply using the env var value if it exists otherwise the property value, ie
bindConstant().annotatedWith(Names.named("value")).to(System.getenv(envVarName) != null && !System.getenv(envVarName).trim().isEmpty() ? System.getenv(envVarName) : properties.getProperty(propertyName));
Which works as expected when the environmental variable is defined and the property is not defined, but when both are defined the property is always used.
Which just leads me to the fact that I know very little about guice and how it works, I have in code a very explicit binding between the property name and this method, but, it just seems to be a default value, something after that is overwriting my value with the one from the property file.
This is super basic, but it's how we do things:
get Properties (sys.properties)
some.random.prop=localhost
iterate through System.getEnv() overriding all the Properties
// Convert SOME_RANDOM_PROP to some.random.prop
properties.put(parseKey(entry.getKey()), entry.getValue());
Now your properties should be defaulted to app.properties and overwritten with matching env.properties, then just bind all he properties.
Names.bindProperties(binder(), properties);
The caveat here is that now System.getEnv() pointless, but since you're using Guice for all your injections this shouldn't really be an issue.

Dynamically setting and getting bean properties in XPages

Just another Java problem (I'm a noob, I know): is it possible to use dynamic property binding in a Custom Control with a dynamic property getter in a Java bean?
I'll explain. I use this feature extensively in my Custom Controls:
<xp:inputTextarea id="DF_TiersM">
<xp:this.value><![CDATA[#{compositeData.dataSource[compositeData.fieldName]}]]></xp:this.value>
This is used in a control where both datasource and the name of the field are passed as parameters. This works, so far so good.
Now, in some cases, the datasource is a managed bean. When the above lines are interpreted, apparently code is generated to get or set the value of ... something. But what exactly?
I get this error: Error getting property 'SomeField' from bean of type com.sjef.AnyRecord which I guess is correct for there is no public getSomeField() in my bean. All properties are defined dynamically in the bean.
So how can I make XPages read the properties? Is there a universal getter (and setter) that allows me to use the name of a property as a parameter instead of the inclusion in a fixed method name? If XPages doesn't find getSomeField(), will it try something else instead, e.g. just get(String name) or so?
As always: I really appreciate your help and answers!
The way the binding works depends on whether or not your Java object implements a supported interface. If it doesn't (if it's just some random Java object), then any properties are treated as "bean-style" names, so that, if you want to call ".getSomeField()", then the binding would be like "#{obj.someField}" (or "#{obj['someField']}", or so forth).
If you want it to fall back to a common method, that's a job for either the DataObject or Map interfaces - Map is larger to implement, but is more standard (and you could inherit from AbstractMap if applicable), while DataObject is basically an XPages-ism but one I'm a big fan of (for reference, document data sources are DataObjects). Be warned, though: if you implement one of those, EL will only bind to the get or getValue method and will ignore normal setters and getters. If you want to use those when present, you'll have to write reflection code to do that (I recommend using Apache BeanUtils).
I have a post describing this in more detail on my blog: https://frostillic.us/f.nsf/posts/expanding-your-use-of-el-%28part-1%29

get a list/array of the names of the the properties of a java bean in the order they appear in the source file

I have a class like
class A {
private String property1;
private String property2;
private String property3;
// constructor , getters , setters
}
it is possible to get a list/array of the names of properties of this class in the order they appear in the source file ? like ["property1", "property2", "property3"]
The answer is that you can't. The information you require is not available at runtime from the .class files.
In some other parts of my code i need to "print" the data of this class in certain order. This class in the real case has a lot of properties and can change (as the order) so, i can write this array/list by myself to get the order i need but if it is possible to get it from the class it would be better for me.
Here are some better ways to solve this problem:
Sort the properties before printing, by name or by type name, or something that makes sense.
Embed an array in the bean class (or another class) that defines the bean property order.
Create a separate metadata file that specifies the bean property order.
You could do some build time pre-processing of your source code to extract the order of the properties and (say) write them to a file. But frankly, I think it is better to detach these aspects; e.g. so that your system integrators / end-users could tweak the property order without changing the source code.
This is not precisely possible. Class#getDeclaredFields makes no guarantee about the ordering of the fields returned. However, in the test I just conducted, the fields were indeed returned in their declaration order.
it is possible to get a list/array of the names of properties of this class
Yes, using Class.getDeclaredFields()
in the order they appear in the source file
No, not with any kind of guarantee unless you parse the source file.

Java .properties files as strongly typed classes

Is there way to get properties files as strongly typed classes?
I guess there are code generators but doing it with annotations would be much cooler.
What I mean is;
foo.properties file
keyFoo = valuefoo
keyBar = valuebar
maybe with
#properties(file="foo.properties")
class foo { }
becomes
class foo {
String getKeyFoo() { }
String getKeyBar() { }
}
if not shall I start an open source project for that?
ADDITION TO QUESTION;
Think we have a foo.properties file with let say more than 10 entries;
and think it is used as a simple configuration file. What I believe is that this configuration entries should be provided as a configuration class with related getXXX methods to other parts of the design. Then rest of the system accesses the configuration via provided class instead of dealing with key names and don't need to bother where configuration comes. Then you can replace this class with a mock when you are testing callers and dependency to file system goes away. On the other hand it is really nice to
get all entries in a strongly typed fashion.
So this issue is a code generation issue behind the scenes, it is nothing related to runtime. But code generation with an external something instead of annotations didn't seemed nice to me. Although I am not very much familiar with annotations, I guess this could be achieved (but I'll keep in mind that annotations can not generate classes as McDowell points)
There are countless of framework that achieve that for XML with various degree of configuration needed. The standard one bundled with Java is JaxB but it is not exactly a one liner xml persistence framework ...
The problem is that using properties file will only works better than XML (or JSON, ...) on the most trivial classes. When the class become a bit more complex, the properties file will become a nightmare. Another problem is that with trivial classes - there is not much difference between Xml and properties.
That means that the scope of the project will be rather limited. Mostly useful for project having loads of simple properties files.
In big application I worked with, strongly-type reading of properties file is done quite often using a simple factory-method.
Foo foo = Foo.loadFrom("foo.properties");
class Foo {
static Foo loadFrom(String fileName) {
Properties props = new Properties();
props.load(...);
Foo foo = new Foo();
foo.setKeyFoo(props.get("KeyFoo"));
...
return foo;
}
...
}
There is a somewhat similar project for doing configuration as statically typed files. It requires to declare an interface, but it fills in the implementation itself:
public interface AppConfig extends Config {
long getTimeout ();
URL getURL ();
Class getHandlerClass ();
}
The Annotation Processing Tool (apt) cannot modify classes (though it can create new ones). In order to modify the class at compile time, you'd probably need to edit the AST (as Project Lombok does). The simplest approach would probably be to generate the classes and then use the generated library as a dependency for other code.
Yet another way is to use a data binding framework that does this. Even one that does not seem to directly support that could work: for example, Jackson JSON processor would allow this to be done by something like:
ObjectMapper m = new ObjectMapper();
MyBean bean = m.convertValue(properties, MyBean.class);
// (note: requires latest code from trunk; otherwise need to write first, read back)
which works as long as entries in Properties map match logical bean properties, and String values can be converted to matching underlying values.
Something like JFig (ugly IMO), Commons Configuration or EasyConf?
If you want to do it statically, its a code generation problem that may be solved quite easily (for each item in file, produce a new getXXX method).
But if you want this at runtime, then you have the problem of having your code referencing method that did not exists at compile time; I don't think it can be done.
(Note that if you are looking for a project idead, the reverse, having an interface with accessor method and annotation, and an implementation generated at runtime, that relies on the annotated methods, can be done.)
The OP would like to map a property file to a Java API such that each named property in the file corresponds to a similarly named getter method in the API. I presume that an application would then use this API to get property values without having to use property name strings.
The conceptual problem is that a property file is fundamentally not a statically typed entity. Each time someone edits a property file they could add new properties, and hence change the "type" of the property file ... and by implication, the signature of the corresponding API. If we checked that there were no unexpected properties when the Java app loaded the properties file, then we've got an explicit dynamic type-check. If we don't check for unexpected (e.g. misnamed) properties, we've got a source of errors. Things get even messier if you want the types of property values to be something other than a String.
The only way you could do this properly would be to invent the concept of a schema for a property file that specified the property names and the types of the property values. Then implement a property file editor that ensures that the user cannot add properties that conflict with the schema.
And at this point we should recognize that a better solution would be to use XML as the property file representation, an XML schema driven editor for editing property files, and JAXP or something like it to map the property file to Java APIs.
I think this will solve your problem
I have written on this property framework for the last year.
It will provide of multiple ways to load properties, and have them strongly typed as well.
Have a look at http://sourceforge.net/projects/jhpropertiestyp/
It is open sourced and fully documented
Here is my short description from SourceForge:
JHPropertiesTyped will give the developer strongly typed properties. Easy to integrate in existing projects. Handled by a large series for property types. Gives the ability to one-line initialize properties via property IO implementations. Gives the developer the ability to create own property types and property io's. Web demo is also available, screenshots shown above. Also have a standard implementation for a web front end to manage properties, if you choose to use it.
Complete documentation, tutorial, javadoc, faq etc is a available on the project webpage.

Categories