How to parse by Spring a name of a variable (key, but not value) from yaml when its name is changing? - spring

I have a yaml file with a structure
section:
subsections:
subsectionName1:
param1: value1
param2: value2
subsectionName2:
param1: value1
param2: value2
I need to parse these properties as List<CustomClass>
#ConfigurationProperties(prefix = "section.subsections")
#Configuration
public class CustomClass {
private final String subsectionName; //the problem is there
private String param1;
private String param2;
//Constructors, getters, setters
How can I do this in Spring?
I see that this works in Micronaut this way:
import io.micronaut.context.annotation.Context;
import io.micronaut.context.annotation.EachProperty;
import io.micronaut.context.annotation.Parameter;
import lombok.EqualsAndHashCode;
#Context
#EachProperty("section.subsections")
#EqualsAndHashCode
public class CustomClass {
private final String subsectionName;
private String param1;
private String param2;
public CustomClass(#Parameter String subsectionName) {
this.subsectionName = subsectionName;
}
//getters, setters...
But I didn't manage to find something similar to io.micronaut.context.annotation.Parameter in Spring.
I need this to use the shared util class which accepts List as a parameter.
Are there any ideas on how to do this?
I really appreciate any help you can provide.

Maybe you can try something like that :
section:
subsections:
subsectionName1: value1,value2
And in your code you need to parse this using #Value annotation and split function of Strings
#Value("#{'${section.subsections:}'.split(',')}")
Set<String> subsections
In that case I use set, but you cant use list if you allow repeated values.

Related

Spring property binding with multiple separation

I have an application.property like this:
somevalue.api.test=something
somevalue.anotherproperty=stuff
I have made a configuration bean like this:
#Configuration
#ConfigurationProperties("somevalue")
public class SomeProperties {
#NotNull
private String apiTest;
#NotNull
private String anotherproperty;
}
Is it possible to refer to api.test like apiTest?
Mainly my issue is that I want to use the somevalue starting point for both property. I know if I don't separate with a dot the apiTest and I use it in this way somevalue.api-test I can refer to that with apiTest in my bean, but in my case it's not possible the renaming. So with dot separation can I achieve the same result or I should create two separate config bean, one refering to somevalue.api and the another only to somevalue?
If you can't rename the property then no, you can't reference it using String apiTest. You need an additional class as follows:
#Configuration
#ConfigurationProperties("somevalue")
public class GcssProperties {
#NotNull
private GcssApiProperties api;
#NotNull
private String anotherproperty;
}
public class GcssApiProperties {
#NotNull
private String test;
}
This should work.

Spring RefreshScope with SpEL deferred Evaluation

I'm having trouble knowing how this is possible or a potential work around. I am looking at configuring variables that are in the form of "foo,bar,baz" into a List as separate elements. Currently the code looks like
#RefreshScope
#Configuration
#Getter
public class fakeConfiguration {
#Value("#{PropertySplitter.toSet('${properties:}')}")
private final Set<String> field = new HashSet<>();
}
#Component("PropertySplitter")
#SuppressWarnings("unused")
public class PropertySplitter {
public Set<String> toSet(String property) {
Set<String> set = new HashSet<>();
if(!property.trim().isEmpty()){
Collections.addAll(set, property.split("\\s*,\\s*"));
}
return set;
}
}
This properly evaluates the String list into a Set however the refreshScope never gets triggered properly. If I use
#Value("${properties:}")
private final String fieldAsString;
I can see the field properly refresh, but I'd like to actively convert the value to a list as it is changed. Is this possible?
In newer version of spring-boot below works for application.properties and Application.yml
#Value("#{${props.list}}")
private List<String> fieldList;
If you use Application.yml you can arrange the objects
props:
list:
- val1
- val2
and then use in code
#Value("${props.list}")
private List<String> ymlList
Last, You can try the below as well
#Value("#{'${props.list}'.split(',')}")
private List<String> myList;

How to map property in application.yml to JsonNode? (Spring)

In a #ConfigurationProperties bean, I could map the customers property of the application.yml file below to List<Customer>, but I would like to instead map it to a Jackson JsonNode. Is this possible? If so, how?
shop:
name: "Sam's Bikes"
customers:
- name: Lucy
age: 26
- name: James
age: 24
This is what I'd like to achieve:
#ConfigurationProperties("shop")
public class ShopProperties() {
private String name;
private JsonNode customers;
}
Since customers in application.yml are in Array of objects format, i would recomend either to collect them into List<Customer> or List<Map<String,Object>> using below code, #Data is lombok annotation, if you are not using lombok add getters and setters
#ConfigurationProperties("shop")
#Data
#Configuration
public class TestConfig {
private String name;
private List<Map<String,Object>> customers; //[{name=Lucy, age=26}, {name=James, age=24}]
}

Spring return selected field from domain

I've the following domain and needs to return selected field in response to client. How can I achieve that using Spring?
public class Vehicle {
private String vehicleId;
private Long dateCreated;
private String ownerId;
private String colourCode;
private String engineNumber;
private String transmission;
//getters & setters
}
My objective is to return only colourCode and transmission fields to client request. I've read about DTO and seems like I can achieve my objective with DTO but I don't find any good example how to implement it. Is DTO is the correct way to achieve my objective ?
Basically you just create VehicleDTO class with parameters you need
public class VehicleDTO {
private String colourCode;
private String transmission;
//getters and setters
}
and then in your code you construct VehicleDTO from your Vehicle class. Fortunately, we have BeansUtils class from Spring, that uses reflection to copy properties of one object to another, because you do not want to repeat logic for copying properties for every object. So it would be something like:
BeanUtils.copyProperties(v1, dto);
At the end your return VehicleDTO in your response instead of Vehicle
You can return IVehicle interface which exposes your properties of choice
public interface IVehicle {
String getTransmission();
String getColourCode();
}
and your Vehicle implents it
public class Vehicle implements IVehicle{ }
There are various ways you can achieve what you want.
You can add relevant usecase / APi specific DTO for the resource.
e.g. If your API return the vehical general details you may want to expose some level of details,
public class VehicleDetailsDTO {
private String colourCode;
private String transmission;
private String engineNumber; //more
//getters and setters
}
You can then either use BeanUtils or Dozzer to convert your Vehical resource to transportable object like your DTO.
BeanUtils : http://commons.apache.org/proper/commons-beanutils/
Dozzer : http://dozer.sourceforge.net/documentation/mappings.html
Assuming you use JSON as output format and Jackson as serialization engine (default in Spring MVC), you can tell Jackson to not serialize null properties. Now you just need to populate the properties you need and can return the original business object.

preprocess configuration values in Spring

In a Spring bean, I need to process a configuration property before using is, e.g.:
#Component
class UsersController {
#Value("${roles}")
private String rolesAsString;
private List<String> roles;
#PostConstruct
public void initRoles() {
// just an example, not necessarily string splitting
roles = rolesAsString.split(",");
}
This works, but I am left with an unneeded member variable 'rolesString'. What would be a clean concise way to only keep the processed value?
Properties is
roles=role1,role2,role3
Code is :
#Value("#{'${roles}'.split(',')}")
private List<String> roles;

Resources