Spring will automatically bind properties defined in application.properties or application.yml to fields defined in #ConfigurationProperties-annotated classes. For instance, in my application.properties I can have:
fizz.buzz=35
fizz.foo=hello
And in my Java code I can have:
#ConfigurationProperties("fizz")
public class FizzProperties {
private Integer buzz;
private String foo;
// ...
}
And at runtime FizzProperties#buzz will get a value of 35 injected into it and FizzProperties#foo will have a value of "hello" injected into it.
I'm wondering what the naming convention is for camel-cased Java fields, and also for hyphens ("-") and periods (".") used in the properties files. For instance, if I had:
fizz.whistle-feather=true
fizz.baz.boo=always
What would their corresponding Java fields need to look like in order for Spring to map and inject them properly?
public class Baz {
private String boo;
}
#ConfigurationProperties("fizz")
public class FizzProperties {
private Integer whistleFeather; // correct?
private Baz baz; // correct?
// ...
}
Are my assumptions correct here or misled (and if misled, how so)? I can't find this explained in the Spring docs.
As stated in spring-boot docs, it uses "relaxed binding", so both properties "whistle-feather" and "whistleFeather" will be mapped to your private Integer whistleFeather, but it's recommended, when possible, to store properties in lower-case kebab format, such as fizz.whistle-feather=10.
So your first case is correct.
The second case is also correct, because dots are used as delimiters in application.properties, while YAML file uses as delimiters both dots and colon.
You also may define nested properties as nested classes to store them in one place like this:
#ConfigurationProperties("fizz")
public class FizzProperties {
private Integer whistleFeather;
private Baz baz;
// getters, setters
public static class Baz {
private String boo;
// getters, setters
}
}
Take a look here for more info about spring-boot properties binding and examples.
Related
I have a java configuration where I create bean using some properties, defined in application.properties. For one of them I have a default value which is pretty long, so I extracted this value to a public static final String field of this configuration, now I want to make #Value use it as a default value.
So eventually I want something like this:
#Configuration
public class MyConfiguration {
public static final String DEFAULT_PROPERTY_VALUE = "long string...";
#Bean("midPriceDDSEndpoint")
public DistributedDataSpace<Long, MidPriceStrategy> midPriceDDSEndpoint(
#Value("${foo.bar.my-property:DEFAULT_PROPERTY_VALUE}") String myPropertyValue) {
... create and return bean...
}
}
However by spring doesn't my field, so I am curious if I can somehow make it lookup it.
One way to fix this, is to access this static field through the configuration bean: #Value(${foo.bar.my-property:#{myConfigurationBeanName.DEFAULT_PROPERTY_VALUE}}), but using this approach makes constructor unreadable, because Value annotation then takes a lot of space(as property name and configuration bean name is longer then in this example). Is there any other way to make spring use static field as a default value for property?
I would do
#Value("${foo.bar.my-property:" + DEFAULT_PROPERTY_VALUE + "}")
#Vyncent's answer is limited in scope because it only works with publicly accessible static constants, since annotation attributes must be compile-time constants. To invoke a static method, use the following:
#Value("${demo.parallelism:#{T(java.lang.Runtime).getRuntime().availableProcessors()}}")
private int parallelism;
This sets parallelism = demo.parallelism JVM variable or gets the number of processors dynamically.
You may just want to inject Environment, and get the value as default like so:
#Configuration
public class MyConfiguration {
public static final String DEFAULT_PROPERTY_VALUE = "long string...";
#Autowired
private Environment env;
#Bean("midPriceDDSEndpoint")
public DistributedDataSpace<Long, MidPriceStrategy> midPriceDDSEndpoint() {
String myPropertyValue = env.getProperty("foo.bar.my-property", DEFAULT_PROPERTY_VALUE);
}
}
I personally think that's a little bit more readable...
I'm not 100% sure, but I think it's not possible. The real question here is why you would need to do something like that? What is the use case? You can always make a simple workaround like
private String getMyPropertyValue() {
return myPropertyValue.equals("some_explicitly_defined_default_value") ? DEFAULT_PROPERTY_VALUE : myPropertyValue;
}
When creating a POJO it is bad practice to set any attributes in the constructor without passing them in because of dependency injection.
If you are setting one of the fields to a UUID value is this acceptable to be generated and set on construction? Or should it be passed in through the constructor?
Or is there a general pattern used for this?
I would definitely have a constructor that accepts a UUID for the reasons you already outlined. (And testing.)
However I would also add a static factory method that only accepts the values you really want to set externally in regular code. So something like this:
public class Foo {
private final UUID id;
private final Bar bar;
Foo(UUID id, Bar bar) {
this.id = id;
this.bar = bar;
}
public static Foo create(Bar bar) {
return new Foo(UUID.randomUUID(), bar);
}
}
I specified the constructor as package-private, which is permissive enough for testing (if you happen to need it), and only leaves one publicly visible way to create instances of the class.
Suppose I have a class com.example.Foo and another class com.sample.Bar which needs to know the fully-qualified name of Foo. If I am a Java novice I might put:
public class Bar {
private String fooName = "com.example.Foo";
//...
}
However, if I refactored Foo to change the name or package, the changes would not be reflected in Bar, unless the IDE is really clever. So it's better to do something like this:
import com.example.Foo;
public class Bar {
private String fooName = Foo.class.getName();
// ...
}
This way, if I refactor Foo, then the change should be picked up by Bar.
Now consider methods. If I have a method name in class Foo and the name needs to be known by Bar, it seems the best I can do is:
public class Bar {
private String bazName = Foo.class.getMethod("bazMethod", Qux.class);
// ...
}
But I haven't actually achieved anything - I still have a string literal "bazMethod" which won't be refactored if the real bazMethod gets renamed.
What I really want to do is something like:
public class Bar {
private String bazName = tellMeTheMethodName((new Foo()).bazMethod(null));
// ...
}
Not sure if this is possible somehow and if there is any way around it.
Now comes the real problem - even if you can sort that out as above, the real thing I am trying to access is an annotation attribute/element name. But annotations are abstract and cannot even be instantiated. So is this possible?
Annotation is just an interface, which you can subclass too! :) For example, annotation
public #interface SomeAnno
{
String attr1();
int attr2();
}
And you want a "statically typed" way to reference names "attr1", "attr2".
This can be done through some elaborate conspiracies among some methods.
String n1 = name( SomeAnno::attr1 );
class MyAnno implements SomeAnno
{
String attr1(){ ... }
MyAnno.attr1()/attr2()/... each triggers a distinct side effect; name(action) compares the side effect of the action, and matches it to one of the attr.
We can generalize this trick to write a universal util that works on any annotation type (actually, any interface type).
SomeAnno anno = proxy(SomeAnno.class);
String n1 = name( anno::attr1 );
But this is really not worth it:) You can just hardcode the name, and do a runtime check (as early as possible) to assert that the name is indeed valid.
In Spring 3.3 I have an entity which is mapped to a database table. In this entity class I have all properies annotated with #JsonProperty, for instance #JsonProperty("ID").
Stepping into the controller a service is called to get such an entity by using a DAO/repository. This works well but when I send this entity back to the requestor using #ResponseBody all properties are sent twice. Once as demanded but one more time beginning lowercase until the first camel case letter occurs.
An example...
public class MyEntity {
#JsonProperty("MYSpecialSuperId")
private String MYSpecialSuperId;
...
public String getMYSpecialSsuperId() {
return this.MYSpecialSuperId;
}
}
After JSON stringifying the result is:
{ "MYSpecialSuperId":""9", "myspecialSuperId":"9" }
Why is the property twice in the result and why is the lettering different???
BTW:
It was not my idea to let Java properties begin with an uppercase letter even yet with more than one uppercase letter.
Jackson's ObjectMapper uses the Java bean pattern. In other words, it expects the following
public class Foo {
public Object bar;
public Object getBar() {...}
public void setBar(Object bar) {...}
}
The getters and setters start with get and set, respectively, followed by the corresponding field name with its first letter capitalized. If you change your code to
public class MyEntity {
#JsonProperty("MYSpecialSuperId")
private String mySpecialSuperId;
...
public String getMySpecialSuperId() {
return this.mySpecialSuperId;
}
}
Note that the field starts with lowercase my instead of uppercase (regardless of the #JsonProperty value), I removed the extra s in getMYSpecialSsuperId and used a lowercase y. So now the field name matches the getter name and jackson knows that the property is the same and doesn't need to serialize twice.
If you have no choice, you can follow what Katona posted in the comments and use
#JsonAutoDetect(getterVisibility=Visibility.NONE)
to make jackson ignore the getters completely and only use the fields to serialize your JSON.
I think you have a typo in your accessor; if it has "SsuperId" it does not match name of the field; and as such field and getter are taken to mean different logical properties.
Let's say I have a class Foo with some primitive instance variables. I initialize these with properties in XML files. Now every Foo also has a Bar as a variable, which in turn has its own properties. Since these are tied to the enclosing object, it would make sense to keep them in the same file. How should I format the XML so that it can initialize the object as well?
Use Spring. It's specifically designed to allow this type of object initialization, including handling inter-object references.
Take a look at XStream, which allows you to trivially serialise/deserialise a Java object hierarchy to/from XML.
At its simplest it'll work with a POJO, which no additional work (no interfaces/base classes etc. required). But you can customise how it serialises and deserialises to rename elements etc. to fit within an existing XML framework.
JAXB is worth a look:
public class JaxbDemo {
#XmlRootElement
public static class Foo {
#XmlElement public Bar bar;
}
public static class Bar {
#XmlAttribute public int baz;
}
public static void main(String[] args) {
String xml = "<foo><bar baz='123'/></foo>";
Foo foo = JAXB.unmarshal(new StringReader(xml), Foo.class);
System.out.println(foo.bar.baz);
}
}
(Public members used for demo purposes.)