diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
index 33ac70dbae..a187ed4a8e 100644
--- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
+++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
@@ -291,6 +291,7 @@ Spring Boot uses a very particular `PropertySource` order that is designed to al
sensible overriding of values, properties are considered in the following order:
. Command line arguments.
+. Properties from `SPRING_APPLICATION_JSON` (inline JSON embedded in an environment variable or system property)
. JNDI attributes from `java:comp/env`.
. Java System properties (`System.getProperties()`).
. OS environment variables.
@@ -333,6 +334,33 @@ default `name`. When running in production, an `application.properties` can be p
outside of your jar that overrides `name`; and for one-off testing, you can launch with
a specific command line switch (e.g. `java -jar app.jar --name="Spring"`).
+[TIP]
+====
+
+The `SPRING_APPLICATION_JSON` properties can be supplied on the
+command line with an environment variable. For example in a
+UN{asterisk}X shell:
+
+----
+$ SPRING_APPLICATION_JSON='{"foo":{"bar":"spam"}}' java -jar myapp.jar
+----
+
+In this example you will end up with `foo.bar=spam` in the Spring
+`Environment`. You can also supply the JSON as
+`spring.application.json` in a System variable:
+
+----
+$ java -Dspring.application.json='{"foo":"bar"}' -jar myapp.jar
+----
+
+or command line argument:
+
+----
+$ java -jar myapp.jar --spring.application.json='{"foo":"bar"}'
+----
+
+or as a JNDI variable `java:comp/env/spring.application.json`.
+====
[[boot-features-external-config-random-values]]
diff --git a/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java b/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java
new file mode 100644
index 0000000000..b5417190f3
--- /dev/null
+++ b/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2012-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.env;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.json.JsonParser;
+import org.springframework.boot.json.JsonParserFactory;
+import org.springframework.core.Ordered;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.Environment;
+import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.MutablePropertySources;
+import org.springframework.core.env.StandardEnvironment;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.context.support.StandardServletEnvironment;
+
+/**
+ * An {@link EnvironmentPostProcessor} that parses JSON from
+ * spring.application.json or equivalently
+ * {@link SpringApplicationJsonEnvironmentPostProcessor} and adds it as a map property
+ * source to the {@link Environment}. The new properties are added with higher priority
+ * than the system properties.
+ *
+ * @author Dave Syer
+ */
+public class SpringApplicationJsonEnvironmentPostProcessor
+ implements EnvironmentPostProcessor, Ordered {
+
+ private static final Log logger = LogFactory
+ .getLog(SpringApplicationJsonEnvironmentPostProcessor.class);
+
+ /**
+ * The default order for the processor.
+ */
+ public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 20;
+
+ private int order = DEFAULT_ORDER;
+
+ @Override
+ public int getOrder() {
+ return this.order;
+ }
+
+ public void setOrder(int order) {
+ this.order = order;
+ }
+
+ @Override
+ public void postProcessEnvironment(ConfigurableEnvironment environment,
+ SpringApplication application) {
+ String json = environment.resolvePlaceholders(
+ "${spring.application.json:${SPRING_APPLICATION_JSON:}}");
+ if (StringUtils.hasText(json)) {
+ try {
+ JsonParser parser = JsonParserFactory.getJsonParser();
+ Map map = parser.parseMap(json);
+ if (!map.isEmpty()) {
+ MapPropertySource source = new MapPropertySource(
+ "spring.application.json", flatten(map));
+ MutablePropertySources sources = environment.getPropertySources();
+ String name = findPropertySource(sources);
+ if (sources.contains(name)) {
+ sources.addBefore(name, source);
+ }
+ else {
+ sources.addFirst(source);
+ }
+ }
+ }
+ catch (Exception e) {
+ logger.warn("Cannot parse JSON for spring.application.json: " + json, e);
+ }
+ }
+ }
+
+ /**
+ * Flatten the map keys using period separator.
+ */
+ private Map flatten(Map map) {
+ Map result = new LinkedHashMap();
+ flatten(null, result, map);
+ return result;
+ }
+
+ private void flatten(String prefix, Map result,
+ Map map) {
+ if (prefix == null) {
+ prefix = "";
+ }
+ else {
+ prefix = prefix + ".";
+ }
+ for (String key : map.keySet()) {
+ String name = prefix + key;
+ Object value = map.get(key);
+ if (value instanceof Map) {
+ @SuppressWarnings("unchecked")
+ Map nested = (Map) value;
+ flatten(name, result, nested);
+ }
+ else {
+ result.put(name, value);
+ }
+ }
+ }
+
+ private String findPropertySource(MutablePropertySources sources) {
+ if (ClassUtils.isPresent(
+ "org.springframework.web.context.support.StandardServletEnvironment",
+ null)
+ && sources
+ .contains(StandardServletEnvironment.JNDI_PROPERTY_SOURCE_NAME)) {
+ return StandardServletEnvironment.JNDI_PROPERTY_SOURCE_NAME;
+
+ }
+ return StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME;
+ }
+
+}
diff --git a/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot/src/main/resources/META-INF/spring.factories
index cf6e8ae70d..aed00315ca 100644
--- a/spring-boot/src/main/resources/META-INF/spring.factories
+++ b/spring-boot/src/main/resources/META-INF/spring.factories
@@ -27,4 +27,5 @@ org.springframework.boot.logging.LoggingApplicationListener
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
-org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor
+org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
+org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor
diff --git a/spring-boot/src/test/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessorTests.java b/spring-boot/src/test/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessorTests.java
new file mode 100644
index 0000000000..9ce7c320cf
--- /dev/null
+++ b/spring-boot/src/test/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessorTests.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2012-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.env;
+
+import org.junit.Test;
+
+import org.springframework.boot.test.EnvironmentTestUtils;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.StandardEnvironment;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Dave Syer
+ */
+public class SpringApplicationJsonEnvironmentPostProcessorTests {
+
+ private SpringApplicationJsonEnvironmentPostProcessor processor = new SpringApplicationJsonEnvironmentPostProcessor();
+
+ private ConfigurableEnvironment environment = new StandardEnvironment();
+
+ @Test
+ public void error() {
+ assertEquals("", this.environment.resolvePlaceholders("${foo:}"));
+ EnvironmentTestUtils.addEnvironment(this.environment,
+ "spring.application.json=foo:bar");
+ this.processor.postProcessEnvironment(this.environment, null);
+ assertEquals("", this.environment.resolvePlaceholders("${foo:}"));
+ }
+
+ @Test
+ public void missing() {
+ assertEquals("", this.environment.resolvePlaceholders("${foo:}"));
+ this.processor.postProcessEnvironment(this.environment, null);
+ assertEquals("", this.environment.resolvePlaceholders("${foo:}"));
+ }
+
+ @Test
+ public void empty() {
+ assertEquals("", this.environment.resolvePlaceholders("${foo:}"));
+ EnvironmentTestUtils.addEnvironment(this.environment,
+ "spring.application.json={}");
+ this.processor.postProcessEnvironment(this.environment, null);
+ assertEquals("", this.environment.resolvePlaceholders("${foo:}"));
+ }
+
+ @Test
+ public void periodSeparated() {
+ assertEquals("", this.environment.resolvePlaceholders("${foo:}"));
+ EnvironmentTestUtils.addEnvironment(this.environment,
+ "spring.application.json={\"foo\":\"bar\"}");
+ this.processor.postProcessEnvironment(this.environment, null);
+ assertEquals("bar", this.environment.resolvePlaceholders("${foo:}"));
+ }
+
+ @Test
+ public void envVar() {
+ assertEquals("", this.environment.resolvePlaceholders("${foo:}"));
+ EnvironmentTestUtils.addEnvironment(this.environment,
+ "SPRING_APPLICATION_JSON={\"foo\":\"bar\"}");
+ this.processor.postProcessEnvironment(this.environment, null);
+ assertEquals("bar", this.environment.resolvePlaceholders("${foo:}"));
+ }
+
+ @Test
+ public void nested() {
+ assertEquals("", this.environment.resolvePlaceholders("${foo:}"));
+ EnvironmentTestUtils.addEnvironment(this.environment,
+ "SPRING_APPLICATION_JSON={\"foo\":{\"bar\":\"spam\",\"rab\":\"maps\"}}");
+ this.processor.postProcessEnvironment(this.environment, null);
+ assertEquals("spam", this.environment.resolvePlaceholders("${foo.bar:}"));
+ assertEquals("maps", this.environment.resolvePlaceholders("${foo.rab:}"));
+ }
+
+ @Test
+ public void prefixed() {
+ assertEquals("", this.environment.resolvePlaceholders("${foo:}"));
+ EnvironmentTestUtils.addEnvironment(this.environment,
+ "SPRING_APPLICATION_JSON={\"foo.bar\":\"spam\"}");
+ this.processor.postProcessEnvironment(this.environment, null);
+ assertEquals("spam", this.environment.resolvePlaceholders("${foo.bar:}"));
+ }
+
+}