Best Approach to load application.yml in spring boot application - spring

I am having Spring Boot application and having application.yml with different properties and loading as below.
#Configuration
#ConfigurationProperties(prefix="applicationprops")
public class ApplicationPropHolder {
private Map<String,String> mapProperty;
private List<String> myListProperty;
//Getters & Setters
}
My Service or Controller Class in which I get this properties like below.
#Service
public ApplicationServiceImpl {
#Autowired
private ApplicationPropHolder applicationPropHolder;
public String getExtServiceInfo(){
Map<String,String> mapProperty = applicationPropHolder.getMapProperty();
String userName = mapProperty.get("user.name");
List<String> listProp = applicationPropHolder.getMyListProperty();
}
}
My application.yml
spring:
profile: dev
applicationprops:
mapProperty:
user.name: devUser
myListProperty:
- DevTestData
---
spring:
profile: stagging
applicationprops:
mapProperty:
user.name: stageUser
myListProperty:
- StageTestData
My questions are
In my Service class i am defining a variable and assigning Propertymap for every method invocation.Is it right appoach?
Is there any other better way I can get these maps without assigning local variable.

There are three easy ways you can assign the values to instance variables in your bean class.
Use the #Value annotation as follows
#Value("${applicationprops.mapProperty.user\.name}")
private String userName;
Use the #PostConstruct annotation as follows
#PostConstruct
public void fetchPropertiesAndAssignToInstanceVariables() {
Map<String, String> mapProperties = applicationPropHolder.getMapProperty();
this.userName = mapProperties.get( "user.name" );
}
Use #Autowired on a setter as follows
#Autowired
public void setApplicationPropHolder(ApplicationPropHolder propHolder) {
this.userName = propHolder.getMapProperty().get( "user.name" );
}
There may be others, but I'd say these are the most common ways.

Hope, you are code is fine.
Just use the below
#Configuration
#ConfigurationProperties(prefix="applicationprops")
public class ApplicationPropHolder {
private Map<String,String> mapProperty;
private List<String> myListProperty;
public String getUserName(){
return mapProperty.get("user.name");
}
public String getUserName(final String key){
return mapProperty.get(key);
}
}
#Service
public ApplicationServiceImpl {
#Autowired
private ApplicationPropHolder applicationPropHolder;
public String getExtServiceInfo(){
final String userName = applicationPropHolder.getUserName();
final List<String> listProp = applicationPropHolder.getMyListProperty();
}
}

Related

Spring Boot Test doesn't load complex configuration properties

I have the following yaml configuration in a Spring Boot application:
document-types:
de_DE:
REPORT: ["Test"]
This is loaded using the following class and works perfectly fine when the SpringBootApplication is started (you can debug the DemoApplication.java to verify):
#Component
#ConfigurationProperties
#Data
public class DocumentTypeConfiguration {
private Map<String, Map<String, List<String>>> documentTypes;
}
But when I execute the following test, the documentTypes aren't loaded (it's null even though the someSrting value is properly set)
#SpringBootTest(classes = {DocumentTypeConfiguration.class, DocumentTypeService.class})
class DocumentTypeServiceTest {
#Autowired
private DocumentTypeConfiguration documentTypeConfiguration;
#Value("${test}")
private String someSrting;
#Autowired
private DocumentTypeService documentTypeService;
#Test
void testFindDocumentType() {
String documentType = "Test";
String result = documentTypeService.getDocumentType(documentType);
String expected = "this";
assertEquals(expected, result);
}
}
Any idea what I might be doing wrong? Or maybe SpringBootTest doesn't support complex types for properties?
Source code and a test can be find here: https://github.com/nadworny/spring-boot-test-properties
This annotation was missing in the test: #EnableConfigurationProperties
So the test class looks like this:
#SpringBootTest(classes = {DocumentTypeConfiguration.class, DocumentTypeService.class})
#EnableConfigurationProperties(DocumentTypeConfiguration.class)
class DocumentTypeServiceTest {
#Autowired
private DocumentTypeConfiguration documentTypeConfiguration;
#Value("${test}")
private String someSrting;
#Autowired
private DocumentTypeService documentTypeService;
#Test
void testFindDocumentType() {
String documentType = "Test";
String result = documentTypeService.getDocumentType(documentType);
String expected = "this";
assertEquals(expected, result);
}
}

Read multiple properties file in one go using Spring Boot?

I went through the link: How to pass a Map<String, String> with application.properties and other related links multiple times, but still its not working.
I'm using Spring Boot and Spring REST example. Link Question: How to by default execute the latest version of endpoint in Spring Boot REST?.
I've created mapping something like this and simply read the mapping
get.customers={GET: '/app-data/customers', VERSION: 'v1'}
post.customers={POST: '/app-data/customers', VERSION: 'v1'}
get.customers.custId={GET: '/app-data/customers/{custId}', VERSION: 'v2'}
Code:
private String resolveLastVersion() {
// read from configuration or something
return "2";
}
Code:
#Component
#ConfigurationProperties
#PropertySource("classpath:restendpoint.properties")
public class PriorityProcessor {
private final Map<String, String> priorityMap = new HashMap<>();
public Map<String, String> getPriority() {
return priorityMap;
}
}
Code:
I suggest the following implementation:
#ConfigurationProperties(prefix="request")
public class ConfigurationProps {
private List<Mapping> mapping;
public List<Mapping> getMapping() {
return mapping;
}
public void setMapping(List<Mapping> mapping) {
this.mapping = mapping;
}
}
Class Mapping will denote the information about the single mapping:
public class Mapping {
private String method;
private String url;
private String version;
public Mapping(String method, String url, String version) {
this.method = method;
this.url = url;
this.version = version;
}
public Mapping() {
}
// getters setters here
}
On the Configuration or spring boot application class (the one with main method):
#EnableConfigurationProperties(ConfigurationProps.class)
In the properties file put:
request.mapping[0].method=get
request.mapping[0].url=/customers
request.mapping[0].version=1
request.mapping[1].method=post
request.mapping[1].url=/students
request.mapping[1].version=2
In Filter (I assume you followed my suggestion from the linked question):
#Component
#Order(1)
public class LatestVersionFilter implements Filter {
private List<Mapping> mappings;
public LatestVersionFilter(ConfigurationProps props) {
this.mappings = props.getMapping();
}
}

how to construct #service in Springboots using a payload variable

I'm quite new in spring boots so I hope this is not a silly question
I have a #Service that needs to initiate a class attribute, this attribute needs a information that comes from the RestPayload in the Controller. I'm not finding the most recommend way to do that.
#RestController
public class UserController {
#Autowired
private UserService userService;
#RequestMapping("/searchUser")
public List<UserWrapper> searchUser(#RequestBody UserWrapper userWrapper) {
List<UserWrapper> returnUserWrapper = userService.findByName(userWrapper);
return returnUserWrapper;
}
}
And the service layer, I would like to be something like:
#Service
public class UserService {
private LdapTemplate ldapTemplate;
public static final String BASE_DN = "xxxxxxx";
#Value( value = "${sample.ldap.url}" )
private String ldapUrl;
#Value( value = "${sample.ldap.base}" )
private String ldapBase;
public UserService() {
}
public UserService(String dn, String password) {
LdapContextSource ctxSrc = new LdapContextSource();
System.out.println(this.ldapUrl);
ctxSrc.setUrl(ldapUrl);
ctxSrc.setBase(ldapBase);
ctxSrc.setUserDn(dn);
ctxSrc.setPassword(password);
ctxSrc.afterPropertiesSet(); // this method should be called.\
this.ldapTemplate = new LdapTemplate(ctxSrc);
}
The String dn and String password will come in the REST Payload but the other properties comes from a properties file.
Hope someone can guide me with best practices
for ldap authentication you should have a look on spring-security:
https://docs.spring.io/spring-security/site/docs/current/reference/html5/#ldap
on the other hand you can access almost any request parameter by just injecting it via a annotation like in these examples:
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-requestheader

How to map configuration objects to java object

I have a spring boot application which is using a spring cloud config.
How can i map a configuration element with some java object.
My config is something like this:
clients:
- id : 1
name: client 1
groups : [a,b]
- id : 2
name: client 2
groups : [a]
And my java object is:
public class ClientInfo {
private String clientId;
private List<String> profiles;
public ClientInfo(String clientId, List<String> pips) {
this.clientId = clientId;
this.profiles = pips;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public List<String> getProfiles() {
return profiles;
}
public void setProfiles(List<String> profiles) {
this.profiles = profiles;
}
}
I want to map my configuration with List
Use below code to configure configuration properties in to java Object,
#Component
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "clients")
public class ClientInfo {
private String id;
private String name;
private List<String> groups;
public String getId(){ return id;}
public String getName(){ return name;}
public List<String> getGroups(){ return groups;}
}
Check following for example http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Inject this class in another class :
#Autowired
private ClientInfo clientInfo;
The above auto wiring will not work if the class is instantiated using "new operator".
Actually I found the reason why it was not working.
All that was needed is to have another class which contains a list of ClientInfo and have #EnableConfigurationProperties and #ConfigurationProperties annotations on it. This is because "clients" in my configuration is a list. After this change we can use #Autowired annotation to inject the configuration.

Trying to use properties file in spring boot

I have a locations.properties file which looks like this:
location.endpoint=testadres,andertestadres
location.test=teststring
I'm trying to read this config file with following class:
#Configuration
#PropertySource("classpath:locations.properties")
public class LocationProperties {
#Value("#{'${location.endpoint}'.split(',')}")
private List<String> locations;
#Value("${location.test}")
private String test;
public String getTest() {
return this.test;
}
public List<String> getLocations() {
return this.locations;
}
//To resolve ${} in #Value
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
But whenever I try to get the strings with getLocations() or getTest() I get null?
Just add .properties or .yml file to your /resources folder. Example
# simple.yml
demo:
connection:
username: sample
sample: My text
and add POJO class
#Component
#ConfigurationProperties(
prefix = "demo.connection",
locations = "classpath:sample.yml"
)
public class SampleSettings {
private String sample;
private String username;
..Getters and Setters mandatory

Resources