diff --git a/spring-boot-modules/spring-boot-properties-2/pom.xml b/spring-boot-modules/spring-boot-properties-2/pom.xml
index c3c3e57251..bd2a35b19d 100644
--- a/spring-boot-modules/spring-boot-properties-2/pom.xml
+++ b/spring-boot-modules/spring-boot-properties-2/pom.xml
@@ -20,6 +20,10 @@
org.springframework.boot
spring-boot-starter
+
+ org.springframework.boot
+ spring-boot-starter-web
+
diff --git a/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/ConfigPropertiesDemoApplication.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/ConfigPropertiesDemoApplication.java
new file mode 100644
index 0000000000..a1e2584b2c
--- /dev/null
+++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/ConfigPropertiesDemoApplication.java
@@ -0,0 +1,16 @@
+package com.baeldung.properties.json;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.context.annotation.ComponentScan;
+
+@SpringBootApplication
+@ComponentScan(basePackageClasses = {JsonProperties.class, CustomJsonProperties.class})
+public class ConfigPropertiesDemoApplication {
+
+ public static void main(String[] args) {
+ new SpringApplicationBuilder(ConfigPropertiesDemoApplication.class).initializers(new JsonPropertyContextInitializer())
+ .run();
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/CustomJsonProperties.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/CustomJsonProperties.java
new file mode 100644
index 0000000000..555711c49b
--- /dev/null
+++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/CustomJsonProperties.java
@@ -0,0 +1,71 @@
+package com.baeldung.properties.json;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties(prefix = "custom")
+public class CustomJsonProperties {
+
+ private String host;
+
+ private int port;
+
+ private boolean resend;
+
+ private Person sender;
+
+ public static class Person {
+
+ private String name;
+ private String address;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public boolean isResend() {
+ return resend;
+ }
+
+ public void setResend(boolean resend) {
+ this.resend = resend;
+ }
+
+ public Person getSender() {
+ return sender;
+ }
+
+ public void setSender(Person sender) {
+ this.sender = sender;
+ }
+}
diff --git a/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/JsonProperties.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/JsonProperties.java
new file mode 100644
index 0000000000..6ada770e3b
--- /dev/null
+++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/JsonProperties.java
@@ -0,0 +1,65 @@
+package com.baeldung.properties.json;
+
+import com.baeldung.properties.json.factory.JsonPropertySourceFactory;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.stereotype.Component;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+
+@Component
+@PropertySource(value = "classpath:configprops.json", factory = JsonPropertySourceFactory.class)
+@ConfigurationProperties
+public class JsonProperties {
+
+ private String host;
+
+ private int port;
+
+ private boolean resend;
+
+ private List topics;
+
+ private LinkedHashMap sender;
+
+ public LinkedHashMap getSender() {
+ return sender;
+ }
+
+ public void setSender(LinkedHashMap sender) {
+ this.sender = sender;
+ }
+
+ public List getTopics() {
+ return topics;
+ }
+
+ public void setTopics(List topics) {
+ this.topics = topics;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public boolean isResend() {
+ return resend;
+ }
+
+ public void setResend(boolean resend) {
+ this.resend = resend;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+}
diff --git a/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/JsonPropertyContextInitializer.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/JsonPropertyContextInitializer.java
new file mode 100644
index 0000000000..e3b713f29b
--- /dev/null
+++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/JsonPropertyContextInitializer.java
@@ -0,0 +1,67 @@
+package com.baeldung.properties.json;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.context.ApplicationContextInitializer;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.PropertySource;
+import org.springframework.core.io.Resource;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class JsonPropertyContextInitializer implements ApplicationContextInitializer {
+
+ private final static String CUSTOM_PREFIX = "custom.";
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
+ try {
+ Resource resource = configurableApplicationContext.getResource("classpath:configprops.json");
+ Map readValue = new ObjectMapper().readValue(resource.getInputStream(), Map.class);
+ Set set = readValue.entrySet();
+ List propertySources = convertEntrySet(set, Optional.empty());
+ for (PropertySource propertySource : propertySources) {
+ configurableApplicationContext.getEnvironment()
+ .getPropertySources()
+ .addFirst(propertySource);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static List convertEntrySet(Set entrySet, Optional parentKey) {
+ return entrySet.stream()
+ .map((Map.Entry e) -> convertToPropertySourceList(e, parentKey))
+ .flatMap(Collection::stream)
+ .collect(Collectors.toList());
+ }
+
+ private static List convertToPropertySourceList(Map.Entry e, Optional parentKey) {
+ String key = parentKey.map(s -> s + ".")
+ .orElse("") + (String) e.getKey();
+ Object value = e.getValue();
+ return covertToPropertySourceList(key, value);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static List covertToPropertySourceList(String key, Object value) {
+ if (value instanceof LinkedHashMap) {
+ LinkedHashMap map = (LinkedHashMap) value;
+ Set entrySet = map.entrySet();
+ return convertEntrySet(entrySet, Optional.ofNullable(key));
+ }
+ String finalKey = CUSTOM_PREFIX + key;
+ return Collections.singletonList(new MapPropertySource(finalKey, Collections.singletonMap(finalKey, value)));
+ }
+
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/factory/JsonPropertySourceFactory.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/factory/JsonPropertySourceFactory.java
new file mode 100644
index 0000000000..dccaae4ad2
--- /dev/null
+++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/factory/JsonPropertySourceFactory.java
@@ -0,0 +1,20 @@
+package com.baeldung.properties.json.factory;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.PropertySource;
+import org.springframework.core.io.support.EncodedResource;
+import org.springframework.core.io.support.PropertySourceFactory;
+
+import java.io.IOException;
+import java.util.Map;
+
+public class JsonPropertySourceFactory implements PropertySourceFactory {
+
+ @Override
+ public PropertySource> createPropertySource(String name, EncodedResource resource) throws IOException {
+ Map readValue = new ObjectMapper().readValue(resource.getInputStream(), Map.class);
+ return new MapPropertySource("json-property", readValue);
+ }
+
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-properties-2/src/main/resources/configprops.json b/spring-boot-modules/spring-boot-properties-2/src/main/resources/configprops.json
new file mode 100644
index 0000000000..1602663775
--- /dev/null
+++ b/spring-boot-modules/spring-boot-properties-2/src/main/resources/configprops.json
@@ -0,0 +1,10 @@
+{
+ "host" : "mailer@mail.com",
+ "port" : 9090,
+ "resend" : true,
+ "topics" : ["spring", "boot"],
+ "sender" : {
+ "name": "sender",
+ "address": "street"
+ }
+}
diff --git a/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/json/JsonPropertiesIntegrationTest.java b/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/json/JsonPropertiesIntegrationTest.java
new file mode 100644
index 0000000000..6b00489b5c
--- /dev/null
+++ b/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/json/JsonPropertiesIntegrationTest.java
@@ -0,0 +1,59 @@
+package com.baeldung.properties.json;
+
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.Arrays;
+
+@RunWith(SpringRunner.class)
+@ContextConfiguration(classes = ConfigPropertiesDemoApplication.class, initializers = JsonPropertyContextInitializer.class)
+public class JsonPropertiesIntegrationTest {
+
+ @Autowired
+ private JsonProperties jsonProperties;
+
+ @Autowired
+ private CustomJsonProperties customJsonProperties;
+
+ @Test
+ public void whenPropertiesLoadedViaJsonPropertySource_thenLoadFlatValues() {
+ Assert.assertEquals("mailer@mail.com", jsonProperties.getHost());
+ Assert.assertEquals(9090, jsonProperties.getPort());
+ Assert.assertTrue(jsonProperties.isResend());
+ }
+
+ @Test
+ public void whenPropertiesLoadedViaJsonPropertySource_thenLoadListValues() {
+ Assert.assertThat(jsonProperties.getTopics(), Matchers.is(Arrays.asList("spring", "boot")));
+ }
+
+ @Test
+ public void whenPropertiesLoadedViaJsonPropertySource_thenNestedLoadedAsMap() {
+ Assert.assertEquals("sender", jsonProperties.getSender()
+ .get("name"));
+ Assert.assertEquals("street", jsonProperties.getSender()
+ .get("address"));
+ }
+
+ @Test
+ public void whenLoadedIntoEnvironment_thenFlatValuesPopulated() {
+ Assert.assertEquals("mailer@mail.com", customJsonProperties.getHost());
+ Assert.assertEquals(9090, customJsonProperties.getPort());
+ Assert.assertTrue(customJsonProperties.isResend());
+ }
+
+ @Test
+ public void whenLoadedIntoEnvironment_thenValuesLoadedIntoClassObject() {
+ Assert.assertNotNull(customJsonProperties.getSender());
+ Assert.assertEquals("sender", customJsonProperties.getSender()
+ .getName());
+ Assert.assertEquals("street", customJsonProperties.getSender()
+ .getAddress());
+ }
+
+}