I'm trying to setup and use a YAML as config file in my Spring Boot 1.5.1 project.
My YAML file looks like the following:
hue:
user: cdKjsOQIRY8hqweAasdmx-WMsn
ip: "http://192.168.1.69"
scenes:
sunstatus:
enabled: true
id: 93yv8JekmAneCU9
group: 1
disable:
enabled: true
id: 93yv8JekmAneCU9
group: 6
It works perfectly fine to read hue.getUser(). However, hue.getScenes() returns null for some reason. My Java code for the Hue Config looks like the following:
#Configuration
#ConfigurationProperties(prefix = "hue")
public class Hue {
private String user;
private String ip;
private Scenes scenes;
/*
* Getters and setters of course
*/
public class Scenes {
private Sunstatus sunstatus;
private Disable disable;
/*
* Getters and setters
*/
public class Sunstatus {
private boolean enabled;
private String id;
private String group;
/*
* Getters and setters
*/
}
public class Disable {
private boolean enabled;
private String id;
private String group;
/*
* Getters and setters
*/
}
}
}
I've tried as well to annotate the each class with prefix as well, both in the format of hue.scenes.sunstatus, scenes.sunstatus and just sunstatus as well.
Additionally I also tried to use the #Value annotation a bit without any luck.
It's the same results if I keep the data in application.yml or in an external file. Can always only reach getUser().
What am I doing wrong here?
I see you are using public non-inner classes for nested configuration, so you should add the #NestedConfigurationProperty instead:
public class Scenes {
#NestedConfigurationProperty
private Sunstatus sunstatus;
#NestedConfigurationProperty
private Disable disable;
Nested properties
You can use the #NestedConfigurationProperty annotation on a field to indicate that a regular (non-inner) class should be treated as if it were nested.
So either add the annotations (if you plan on using the classes elsewhere) or make them public static.
try this.
#Configuration
#ConfigurationProperties(prefix = "hue")
public class Hue {
private String user;
private String ip;
private Scenes scenes = new Scenes();
/*
* Getters and setters of course
*/
public class Scenes {
private Sunstatus sunstatus = new Sunstatus();
private Disable disable = new Disable();
/*
* Getters and setters
*/
public class Sunstatus {
private boolean enabled;
private String id;
private String group;
/*
* Getters and setters
*/
}
public class Disable {
private boolean enabled;
private String id;
private String group;
/*
* Getters and setters
*/
}
}
}
Related
I'm using PMD v3.12 in my current project.
I have a POJO with some properties:
public class Person {
private String name;
private String surname;
private String state;
private String zip;
private String town;
private Integer id;
private LocalDate dateOfBirth;
private String locationOfBirth;
// GETTERS & SETTERS, HASHCODE, TOSTRING
.
.
.
}
I added an inner Builder class for this Pojo:
public class Person {
private String name;
private String surname;
private String state;
private String zip;
private String town;
private Integer id;
private LocalDate dateOfBirth;
private String locationOfBirth;
// GETTERS & SETTERS, HASHCODE, TOSTRING
...
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final Person person;
public Builder() {
this.person = new Person();
}
public Builder name(String name) {
this.person.setName(name);
return this;
}
// Other Methods to build an instance
public Person build() {
return this.person;
}
}
}
Now when PMD is executed, it tells me that the class Person violates TooManyMethods and should be refactored, pointing to the line number, where the inner class begins.
Since i don't want to refactor my Builder, i tried adding an exclusion to the exclude-pmd.properties file, but it doesn't work:
org.my.path.to.my.file.Person=TooManyMethods
I also tried:
org.my.path.to.my.file.Person.Builder=TooManyMethods
org.my.path.to.my.file.Builder=TooManyMethods
and i tired adding #SuppressWarnings("PMD") on both, the parent class and the inner class, but nothing worked.
I am aware that lombok exists, but in my current company it's not allowed, also changing the settings of PMD to allow more Methods to a class is not possible.
Any help is appreciated, thanks in advance!
i have this in Application.yaml:
override:
email:
enabled: true
value: "test#mycompany.com"
phone:
enabled: true
value: "+420666666666"
How do I make a single class configuration with these values?
I tried this:
public class RecipientOverrideConfig {
#Configuration
#ConfigurationProperties("override.email")
#Data
public class EmailOverride{
Boolean enabled;
String value;
}
#Configuration
#ConfigurationProperties("override.phone")
#Data
public class SmsOverride{
Boolean enabled;
String value;
}
}
But is there a better way to do this?
I suggest making the whole class a ConfigurationProperties
#ConfigurationProperties("override")
public class RecipientOverrideProperties {
private OverrideConfig email;
private OverrideConfig phone;
public class OverrideConfig {
private Boolean enabled;
private String value;
}
// getters and setters were omitted for brevity
}
And then autowire that into your configuration:
#Configuration
public class RecipientOverrideConfig {
#Autowired // or even better, use constructor injection
private RecipientOverrideProperties overrideProperties;
}
I have a group of properties as follow:
spring.kafka.producer.edwh.bootstrap-servers=localhost:9092
spring.kafka.producer.edwh.properties.enable.idempotence=true
spring.kafka.producer.edwh.retries=10
spring.kafka.producer.edwh.transaction-id-prefix=slv
spring.kafka.producer.edwh.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer
spring.kafka.producer.edwh.properties.spring.json.add.type.headers=false
... And I want to map in a class like this by using #ConfigurationProperties(prefix = "spring.kafka.producer.edwh"):
#ConfigurationProperties(prefix = "spring.kafka.producer.edwh")
public class EdwhKafkaProducerConfig {
private String bootstrap_servers;
private String properties_enable_idempotence;
private int retries;
private String transaction_id_prefix;
private String value_serializer;
private boolean properties_spring_json_add_type_headers;
}
... How can I do?
The dotted properties denote separate objects. So if you have
mail.additionalHeaders.redelivery=true
mail.additionalHeaders.secure=true
mail.credentials.username=john
mail.credentials.password=password
Then your config class can look like this:
#ConfigurationProperties(prefix = "mail")
public class ConfigProperties {
private AdditionalHeaders additionalHeaders;
private Credentials credentials;
// getters setters
public class AdditionalHeaders {
private boolean redelivery;
private boolean secure;
// getters setters
}
public class Credentials {
private String username;
private String password;
// getters setters
}
}
Have a look here:
https://www.baeldung.com/configuration-properties-in-spring-boot
If you are using Spring Boot, then you need to annotate your main application class with, in your case:
#EnableConfigurationProperties(value = EdwhKafkaProducerConfig.class)
You may also need to define public accessor methods for your configuration properties.
According to Spring Boot documentation, properties can be grouped and a property may appear in more than one group. But at the moment when we create a property class marked with #ConfigurationProperties(prefix="test1") the group name will be the prefix which is test1. Now if I have another property class for example with prefix as "test2" how can I say this latter one has a property from the group test1?
--- UPDATE ---
Added nested class but it's not working
#Configuration
#Profile({"wmx"})
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "myapp.wmx", locations = {"classpath:application-wmx.properties", "classpath:myapp-env.properties"})
public class WmxProperties {
/**
* The WMX implementation to be loaded.
*/
#NotNull(message = "Must be configured.")
private ProfileEnum profile;
//#ConfigurationProperties(locations = "classpath:myapp-env.properties")
public static class Env {
/**
* Host name for WMX.
*/
private String host;
/**
* Port number for WMX.
*/
//#Pattern(regexp = "^[1-9]\\d*$", message = "Positive port number only.")
private Integer port;
/**
* Provider name.
*/
#NotBlank
private String providerName;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public String getProviderName() {
return providerName;
}
public void setProviderName(String providerName) {
this.providerName = providerName;
}
}
public ProfileEnum getProfile() {
return profile;
}
public void setProfile(ProfileEnum profile) {
this.profile = profile;
}
}
The commented annotation #ConfigurationProperties on the inner class is done after failing my tests. Spring doesn't load those properties with or without the annotation unless they are in the same property file, in this case application-emx.properties. Why is that? I want to separate these properties
=== RESOLVED ====
I noticed that I had to add a field of type the nested class with getter/setter methods otherwise Spring won't load the properties in the nested class
You can compose them with help of inner classes:
Property file
test1.property1=...
test1.test2.property2=...
test1.test2.property3=...
Java/Spring mapping:
import javax.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
#Getter
#Setter
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties(locations = "classpath:myapp.properties")
public class ApplicationProperties {
private String property1;
private Test2 test2;
#Getter
#Setter
#ConfigurationProperties(prefix = "test2")
public static class Test2 {
#NotNull
private String property2;
#NotNull
private String property3;
}
}
We had success with this approach, because java composition mimics structure of property file. Also properties are validatable, so you can fail fast if configuration is not right.
Downside of this approach is that properties are mutable.
If your properties file is getting too big, your application most probably has wider problems.
The annotation processor automatically considers inner classes as nested properties. Make sure you have getters and setters defined.
#ConfigurationProperties(prefix="server")
public class ServerProperties {
private String name;
private Host host;
// ... getter and setters !!!
public static class Host {
private String ip;
private int port;
// ... getter and setters !!!
}
}
The same effect can be achieved with non-inner class but you should use the #NestedConfigurationProperty annotation on a field to indicate that a regular (non-inner) class should be treated as if it were nested.
#ConfigurationProperties(prefix="server")
public class ServerProperties {
private String name;
#NestedConfigurationProperty
private Host host;
// ... getter and setters !!!
}
public class Host {
private String ip;
private int port;
// ... getter and setters
}
During my initial approach of a Java application development with MongoDB, I find that my code doesn't look quite right with a flat Java class design and using inner classes seems to be a better approach. I am wondering how others design their Java classes in the regard and potential issues with inner classes for all embedded documents in DB. Here is a sample:
public class Account{
private String userName;
private String password;
//...
private Profile profile;
//...
public static class Profile{
//...
private Address address;
private List<Comment> comments;
//...
public static class Address {
// ...
}
public static class Comment {
// ...
}
}
}
Is the above nested class design better to a flat class design as the followings?
public class Account{
private String userName;
private String password;
//...
private Profile profile;
//...
}
public class Profile{
//...
private Address address;
private List<Comment> comments;
//...
}
public class Address {
// ...
}
public class Comment {
// ...
}