Where to Put SPRING_APPLICATION_JSON When Testing a Spring Boot Application?
Introduction
You have a Spring Boot application whose configuration is supposed to arrive through an environment variable called SPRING_APPLICATION_JSON. In production, your platform team sets it. Now you need to run the app, or its tests, on your own machine, and the question is:
Where do I put
SPRING_APPLICATION_JSON?
The short answer: it goes in the environment of the JVM process that runs your application or your tests. It does not go in application.properties and it does not go in your Java code. Which place that is depends on how you start the process:
| How you run it | Where the variable goes |
|---|---|
| Terminal | Prefix the command, or export it |
| IntelliJ IDEA | Run/Debug configuration → Environment variables |
| Eclipse | Run Configurations → Environment tab |
| VS Code | env in launch.json, or java.test.config for tests |
| Maven tests | Surefire <environmentVariables>, or the shell |
Maven spring-boot:run | Spring Boot plugin <environmentVariables>, or the shell |
| Gradle | environment(...) on the test / bootRun task |
| Docker | -e SPRING_APPLICATION_JSON=... |
| Docker Compose | environment: block |
| Kubernetes | env: entry in the container spec |
| JUnit test code | Usually not the env var. Use @SpringBootTest(properties = ...) or @TestPropertySource |
The rest of this article explains why, how Spring Boot handles the variable, and how to prove it was loaded. I checked the Spring Boot behavior below against the current reference documentation (Spring Boot 4.1.x) and Javadoc. IDE menus and plugin settings change between versions, so treat those sections as guidance and confirm against your IDE’s docs.

What Is SPRING_APPLICATION_JSON?
SPRING_APPLICATION_JSON is an operating-system environment variable whose value is a JSON document. When a Spring Boot application starts, it parses that JSON, flattens it into ordinary Spring properties, and adds them to the Spring Environment.
The reference documentation shows this example: SPRING_APPLICATION_JSON='{"my":{"name":"test"}}' java -jar myapp.jar, which results in my.name=test in the Spring Environment. spring
Spring Boot supports two equivalent names for the same feature:
SPRING_APPLICATION_JSON, an environment variablespring.application.json, a JVM system property, a command-line argument, or (in application servers) a JNDI value
The same JSON can be supplied through any of them:
java -Dspring.application.json='{"my":{"name":"test"}}' -jar myapp.jar
java -jar myapp.jar --spring.application.json='{"my":{"name":"test"}}'Why Does Spring Boot Support JSON in an Environment Variable?
The official docs give the reason: environment variables and system properties often have restrictions that mean some property names cannot be used, so Spring Boot lets you encode a block of properties into a single JSON structure. spring
The restriction is real. Most shells do not allow dots or dashes in environment variable names, so a property like app.mail.smtp.host cannot be an environment variable name directly. Spring Boot’s relaxed binding works around this with names like APP_MAIL_SMTP_HOST, but that has drawbacks:
- Names become ambiguous (
APP_MAIL_SMTP_HOSTcould map to several property shapes). - Lists and maps get awkward (
APP_HOSTS_0_NAME). - You end up with many variables for one logical config block.
JSON avoids this. One variable carries a whole structure, with the original property names intact. It is especially handy on platforms where you can only set a few environment variables per service.
Environment Variables vs. System Properties vs. Files vs. Test Config
Many mix-ups come from treating these as interchangeable. They are separate mechanisms:
| Mechanism | What it is | Example | Who reads it |
|---|---|---|---|
| Environment variable | Set in the OS process environment before the JVM starts | SPRING_APPLICATION_JSON='{...}' | System.getenv(); Spring Boot |
| JVM system property | Passed to the JVM with -D (or set with System.setProperty) | -Dspring.application.json='{...}' | System.getProperty(); Spring Boot |
application.properties | A file on the classpath or disk, loaded by Spring Boot’s config data loader | app.mail.sender=a@b.c | Spring Boot |
application.yml / .yaml | Same as above, in YAML | app:\n mail:\n sender: a@b.c | Spring Boot |
| Test properties | Properties declared on a test: @SpringBootTest(properties=...), @TestPropertySource, @DynamicPropertySource | @TestPropertySource(properties = "app.x=1") | Spring’s test framework |
| Spring test configuration | Beans and profiles that alter the test context: @TestConfiguration, @ActiveProfiles | @ActiveProfiles("test") | Spring’s test framework |
Two points to remember:
SPRING_APPLICATION_JSONis an environment variable, so it must exist before the JVM starts. A Java test cannot reliably create it for itself. The JVM’s environment is effectively read-only from Java code.-DSPRING_APPLICATION_JSON=...is not the documented form. The documented system property is the dotted, lowercasespring.application.json.
How Spring Boot Reads and Processes It
At startup, SpringApplication prepares the Environment and runs EnvironmentPostProcessor implementations. One of them, SpringApplicationJsonEnvironmentPostProcessor, does this work. Its Javadoc says it parses JSON from spring.application.json or equivalently SPRING_APPLICATION_JSON and adds it as a map property source to the Environment, with higher priority than the system properties. (In Spring Boot 4 the class lives in the org.springframework.boot.support package, whereas older versions used org.springframework.boot.env.) spring
The steps are:
- Boot finds the value of
spring.application.json(the env varSPRING_APPLICATION_JSONresolves to it). - It parses the JSON into a map.
- It flattens nested objects into dotted keys.
- It registers the result as a property source (named
spring.application.json).
How JSON keys become Spring properties
Nested objects become dotted names. Arrays become indexed names:
json
{
"app": {
"mail": {
"sender": "noreply@example.com",
"retries": 3,
"smtp": { "host": "smtp.test.local", "port": 2525 },
"allowed-domains": ["example.com", "example.org"]
}
}
}That produces these properties:
properties
app.mail.sender=noreply@example.com
app.mail.retries=3
app.mail.smtp.host=smtp.test.local
app.mail.smtp.port=2525
app.mail.allowed-domains[0]=example.com
app.mail.allowed-domains[1]=example.orgThe [index] form is the same one used when YAML lists are flattened, and Spring’s Binder can bind it to a List or Set.
Two consequences:
- JSON key names must match property names. The JSON layer does not translate
senderAddresstosender-address. Once the properties are in theEnvironment,@ConfigurationPropertiesrelaxed binding applies as usual, but a plain@Value("${...}")needs the exact name. Prefer lowercase kebab-case (sender-address). - A typo does not raise an error. A wrongly spelled but valid key is just an extra property nobody reads.
A note on null
The docs warn that null values from the JSON are added to the property source, but Spring’s PropertySourcesPropertyResolver treats null properties as missing, so JSON cannot override lower-order sources with null. You cannot use {"app":{"x":null}} to “unset” a value from application.properties. spring
What happens with invalid JSON?
A GitHub change titled “Throw an exception on invalid syntax in SPRING_APPLICATION_JSON” removed the code that used to catch the parse failure and only log a warning. So in modern versions, malformed JSON should make startup fail with an exception, and you should look at the top of the stack trace. I could not confirm the exact release notes wording, so check your Boot version if you depend on this.
The Example Application
The examples below use one small app so every section is comparable.
java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties(MailProperties.class)
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}java
package com.example.demo;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "app.mail")
public record MailProperties(String sender, int retries, Smtp smtp, List<String> allowedDomains) {
public record Smtp(String host, int port) {
}
}And a default in src/main/resources/application.properties:
properties
app.mail.sender=default@example.com
app.mail.retries=1The JSON we want to inject:
json
{"app":{"mail":{"sender":"json@example.com","smtp":{"host":"smtp.test.local","port":2525}}}}I have not compiled or executed these examples, so run them once in your own project.
Where to Put It, Tool by Tool
Command line
Linux / macOS (bash, zsh): single quotes stop the shell from touching the double quotes inside the JSON.
shell
SPRING_APPLICATION_JSON='{"app":{"mail":{"sender":"json@example.com"}}}' java -jar target/demo-0.0.1-SNAPSHOT.jarOr export it for the whole session:
shell
export SPRING_APPLICATION_JSON='{"app":{"mail":{"sender":"json@example.com"}}}'
java -jar target/demo-0.0.1-SNAPSHOT.jarWindows PowerShell:
powershell
$env:SPRING_APPLICATION_JSON = '{"app":{"mail":{"sender":"json@example.com"}}}'
java -jar target\demo-0.0.1-SNAPSHOT.jarWindows cmd.exe: no surrounding quotes.
bat
set SPRING_APPLICATION_JSON={"app":{"mail":{"sender":"json@example.com"}}}
java -jar target\demo-0.0.1-SNAPSHOT.jarMaven
A Maven build involves two separate JVM processes you might care about: the one running your app (spring-boot:run) and the forked one running your tests (Surefire).
Quickest option, from the shell. Forked processes inherit the parent environment:
shell
SPRING_APPLICATION_JSON='{"app":{"mail":{"sender":"ci@example.com"}}}' ./mvnw test
SPRING_APPLICATION_JSON='{"app":{"mail":{"sender":"dev@example.com"}}}' ./mvnw spring-boot:runPermanent option for tests, in pom.xml (Surefire’s environmentVariables):
xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<environmentVariables>
<SPRING_APPLICATION_JSON>{"app":{"mail":{"sender":"ci@example.com"}}}</SPRING_APPLICATION_JSON>
</environmentVariables>
</configuration>
</plugin>
</plugins>
</build>If you also run integration tests with Failsafe, configure that plugin the same way. Surefire and Failsafe are configured separately.
For spring-boot:run, the Spring Boot Maven plugin has its own environmentVariables setting:
xml
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<environmentVariables>
<SPRING_APPLICATION_JSON>{"app":{"mail":{"sender":"dev@example.com"}}}</SPRING_APPLICATION_JSON>
</environmentVariables>
</configuration>
</plugin>Gradle
Gradle Kotlin DSL (build.gradle.kts):
kotlin
tasks.withType<Test> {
environment(
"SPRING_APPLICATION_JSON",
"""{"app":{"mail":{"sender":"ci@example.com"}}}"""
)
}
tasks.named<org.springframework.boot.gradle.tasks.run.BootRun>("bootRun") {
environment(
"SPRING_APPLICATION_JSON",
"""{"app":{"mail":{"sender":"dev@example.com"}}}"""
)
}Gradle Groovy DSL (build.gradle):
groovy
tasks.named('test') {
environment 'SPRING_APPLICATION_JSON', '{"app":{"mail":{"sender":"ci@example.com"}}}'
}
tasks.named('bootRun') {
environment 'SPRING_APPLICATION_JSON', '{"app":{"mail":{"sender":"dev@example.com"}}}'
}From the shell, SPRING_APPLICATION_JSON='...' ./gradlew test also works. But Gradle may decide the test task is up to date and skip it, because a shell variable is not a declared task input. If nothing seems to run, use ./gradlew cleanTest test.
IntelliJ IDEA
- Open Run | Edit Configurations…
- Select your JUnit or Spring Boot configuration (or, to apply to all future JUnit runs, Edit configuration templates… → JUnit).
- Open Modify options and enable Environment variables.
- Enter the variable as
NAME=value, with the raw JSON and no surrounding quotes:
text
SPRING_APPLICATION_JSON={"app":{"mail":{"sender":"ide@example.com"}}}IDE-specific caveats:
- IntelliJ’s field uses
;to separate multiple variables, so a JSON value containing a semicolon needs care. - If IntelliJ is set to delegate test runs to Gradle or Maven, the environment that matters is the one in your build script, not the run configuration. This is an IDE behavior, not a Spring Boot one.
Eclipse / Spring Tools
- Run → Run Configurations… (or Debug Configurations…).
- Choose your JUnit or Java Application configuration.
- Open the Environment tab and click New…
- Name:
SPRING_APPLICATION_JSON
Value:{"app":{"mail":{"sender":"eclipse@example.com"}}}(raw JSON, no quotes)
Each JUnit run gets its own generated launch configuration, so an environment variable you add to one class’s configuration will not automatically apply to another class.
VS Code
For running the application with the Java debugger, add an env block to .vscode/launch.json. JSON inside a JSON string needs its quotes escaped:
json
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Demo Application",
"request": "launch",
"mainClass": "com.example.demo.DemoApplication",
"env": {
"SPRING_APPLICATION_JSON": "{\"app\":{\"mail\":{\"sender\":\"vscode@example.com\"}}}"
}
}
]
}For tests run from the Testing view, the Java test runner reads the java.test.config setting in .vscode/settings.json:
json
{
"java.test.config": {
"env": {
"SPRING_APPLICATION_JSON": "{\"app\":{\"mail\":{\"sender\":\"vscode-test@example.com\"}}}"
}
}
}I did not re-verify this setting against the extension’s current documentation, so confirm it in your version. If VS Code runs tests through Maven or Gradle, the build-tool configuration above applies instead.
Docker
shell
docker run --rm \
-e SPRING_APPLICATION_JSON='{"app":{"mail":{"sender":"docker@example.com"}}}' \
my-spring-app:latestConfirm the container actually received it:
shell
docker exec <container-id> printenv SPRING_APPLICATION_JSONDocker Compose
yaml
services:
api:
image: my-spring-app:latest
ports:
- "8080:8080"
environment:
SPRING_APPLICATION_JSON: '{"app":{"mail":{"sender":"compose@example.com","retries":5}}}'Compose interpolates $ characters. If your JSON contains a literal $, write $$.
Kubernetes
Inline in a Deployment:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-api
spec:
replicas: 1
selector:
matchLabels:
app: demo-api
template:
metadata:
labels:
app: demo-api
spec:
containers:
- name: api
image: my-spring-app:latest
env:
- name: SPRING_APPLICATION_JSON
value: '{"app":{"mail":{"sender":"k8s@example.com"}}}'Or from a ConfigMap, which keeps the JSON out of the Deployment:
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: demo-api-config
data:
SPRING_APPLICATION_JSON: |-
{"app":{"mail":{"sender":"cm@example.com"}}}yaml
env:
- name: SPRING_APPLICATION_JSON
valueFrom:
configMapKeyRef:
name: demo-api-config
key: SPRING_APPLICATION_JSONAvoid putting secrets in a plain ConfigMap or inline value. Use a Kubernetes Secret (via secretKeyRef), or mount secrets as files. Spring Boot supports importing config from mounted directories with spring.config.import=configtree:.
JUnit and Spring Boot Tests
This is where most confusion starts, so here is the key idea:
A
@SpringBootTeststarts a realSpringApplication, so it honorsSPRING_APPLICATION_JSONif the variable exists in the test JVM’s environment. But you should not try to create the variable from inside the test.
You have four options.
Option 1: Provide the variable to the test JVM, then verify it
Use the Maven, Gradle, or IDE setup above, then add a test that proves it arrived:
java
package com.example.demo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
@SpringBootTest
class SpringApplicationJsonLoadedTest {
@Autowired
private Environment environment;
@Test
void propertiesFromSpringApplicationJsonAreVisible() {
assumeTrue(System.getenv("SPRING_APPLICATION_JSON") != null,
"SPRING_APPLICATION_JSON is not set for this JVM");
assertThat(environment.getProperty("app.mail.sender")).isEqualTo("ci@example.com");
}
}The assumeTrue line makes the test skip (rather than fail) on machines where the variable is absent. Remove it in CI if the variable is mandatory.
A plain JUnit test without a Spring context never triggers this mechanism, because it is SpringApplication that parses the variable.
Option 2: Use test-native properties (usually the best choice)
If the goal is simply to set property values in a test, skip JSON:
java
@SpringBootTest(properties = {
"app.mail.sender=test@example.com",
"app.mail.smtp.host=localhost",
"app.mail.smtp.port=2525"
})
class MailServiceTest {
// ...
}Or:
java
import org.springframework.test.context.TestPropertySource;
@SpringBootTest
@TestPropertySource(properties = "app.mail.sender=test@example.com")
class MailServiceTest2 {
// ...
}Or, for values computed at runtime (such as a Testcontainers port), use @DynamicPropertySource:
java
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
@SpringBootTest
class MailServiceTest3 {
@DynamicPropertySource
static void registerProperties(DynamicPropertyRegistry registry) {
registry.add("app.mail.smtp.port", () -> 2525);
}
}These are also the highest-precedence property sources in Boot’s order, as you will see next.
Option 3: Pass JSON through the spring.application.json property
If you must exercise the JSON path itself, you can pass the dotted property form as a test property:
java
@SpringBootTest(properties =
"spring.application.json={\"app\":{\"mail\":{\"sender\":\"inline@example.com\"}}}")
class InlineJsonTest {
// ...
}The post-processor reads spring.application.json from the Environment, which is why this should work, but I have not executed this exact form. Confirm it with an Environment assertion like the one in Option 1. Note that this tests the JSON parsing, not the environment variable name.
Option 4: Profile-based test files
For a fixed, reviewable set of test values, the boring approach is often best. Create src/test/resources/application-test.yml:
yaml
app:
mail:
sender: "test@example.com"
smtp:
host: "localhost"
port: 2525and activate it:
java
import org.springframework.test.context.ActiveProfiles;
@SpringBootTest
@ActiveProfiles("test")
class MailServiceProfileTest {
// ...
}What not to do
Calling System.setProperty("spring.application.json", ...) in a static block can work, but it leaks into every later test in the same JVM. Libraries that mutate environment variables at runtime rely on reflection hacks that can break on newer Java versions. Neither is recommended when the built-in test mechanisms above exist.
Property Precedence
Spring Boot merges many property sources. The current reference documentation lists them from lowest to highest priority, and later sources override earlier ones. Here is the part relevant to this topic:
- Default properties
@PropertySourceon@Configurationclasses- Config data (
application.properties/.yml) random.*values- OS environment variables
- Java system properties
- JNDI attributes
- Servlet context/config init parameters
SPRING_APPLICATION_JSON- Command-line arguments
propertiesattribute on@SpringBootTestand test slices@DynamicPropertySource@TestPropertySource- Devtools global settings, if devtools is active
(Source: the Externalized Configuration page of the Spring Boot reference, version 4.1.x.)
What this means in practice:
| Scenario | Winner |
|---|---|
application.properties sets app.mail.sender, JSON also sets it | JSON |
A -Dapp.mail.sender=x system property and the JSON both set it | JSON |
An APP_MAIL_SENDER env var and the JSON both set it | JSON |
The JSON and --app.mail.sender=x on the command line | Command line |
The JSON and @SpringBootTest(properties = "app.mail.sender=x") | Test properties |
The JSON and @TestPropertySource | @TestPropertySource |
Also, precedence works per property, not per source. If the JSON only sets app.mail.sender, then app.mail.retries still comes from application.properties. That is why partial JSON overrides are convenient: you only ship what differs.
Common Mistakes
1. Putting it in application.properties. That file is for the properties themselves. Write app.mail.sender=... there directly. Wrapping JSON in a properties file is not the documented use.
2. Setting it in the wrong process. A variable exported in one terminal does not affect an IDE launched from the desktop, and a variable in an IDE run configuration does not affect ./mvnw test in a terminal. Always ask: which process actually launches the JVM?
3. Quoting mistakes.
- Bash needs single quotes around the JSON.
- Windows
cmdneeds no quotes. - IDE environment fields need no quotes.
- JSON embedded in another JSON file (
launch.json) needs escaped\".
4. Invalid JSON. JSON allows double quotes only, with no single-quoted strings, no trailing commas, and no comments. {'app': {...}} is not valid JSON.
5. Confusing the env var with a system property. SPRING_APPLICATION_JSON goes in the environment. -Dspring.application.json goes on the JVM arguments. They are two entry points for one feature, and they are set in different places.
6. Wrong key names. Valid JSON with a misspelled key loads silently and does nothing.
7. Expecting JSON to beat command-line or test properties. It doesn’t, as shown above.
8. Expecting null to remove a value. It cannot override a lower-priority value.
9. Compose and Kubernetes YAML quoting. Unquoted JSON in YAML can be parsed as a YAML flow mapping instead of a string. Quote it with single quotes, as shown above. In Compose, escape a literal $ as $$.
10. Putting secrets in it. Environment variables appear in docker inspect, process inspection tools, and CI logs. Use secret stores for credentials.
11. Stale Gradle results. Tests skipped as up to date because the environment changed outside Gradle’s knowledge (see above).
How to Verify the Configuration Was Loaded
Work from the outside in.
Step 1: Is the variable in the process at all?
shell
printenv SPRING_APPLICATION_JSON # local shell
docker exec <container> printenv SPRING_APPLICATION_JSON # Docker
kubectl exec <pod> -- printenv SPRING_APPLICATION_JSON # KubernetesIf this prints nothing, Spring Boot is not the problem.
Step 2: Is it valid JSON? Paste it into a validator, or run:
shell
printenv SPRING_APPLICATION_JSON | python3 -m json.toolStep 3: Does the Spring Environment see the property? Add a temporary check:
java
package com.example.demo;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
@Configuration(proxyBeanMethods = false)
class StartupCheck {
@Bean
CommandLineRunner printMailSender(Environment env) {
return args -> System.out.println("app.mail.sender = " + env.getProperty("app.mail.sender"));
}
}Delete it once you are done.
Step 4: Which source won? Spring Boot Actuator’s env endpoint shows every property source and the winning value for a key. Add spring-boot-starter-actuator, expose the endpoint, and, for local debugging only, show values (they are hidden by default):
properties
management.endpoints.web.exposure.include=env
management.endpoint.env.show-values=ALWAYSThen request /actuator/env/app.mail.sender. The response lists the property sources that define the property, so you can see whether the JSON source or something with higher priority supplied the final value. The reference docs note that the env and configprops endpoints are useful for diagnosing why a property has a particular value. Do not enable show-values=ALWAYS in production.
Step 5: Is your binding correct? Inject your @ConfigurationProperties bean in a test and assert on its fields, not just on the raw Environment.
Troubleshooting Checklist
| Symptom | Likely cause | What to do |
|---|---|---|
| App ignores the JSON completely | Variable set in a different process | printenv inside the actual process; check the IDE/Maven/Gradle configuration |
| Startup fails with a parse error | Invalid JSON, or quotes mangled by the shell | Validate the JSON; check quoting rules for your shell |
Value is still the application.properties default | Wrong key name, or a higher-precedence source is winning | Check the key spelling; inspect /actuator/env/<key> |
| Value differs in tests only | @TestPropertySource, @DynamicPropertySource, or @SpringBootTest(properties=...) overrides it | Search the test class hierarchy for those annotations |
| Works in IntelliJ, fails in CI | IDE config not mirrored in the build | Put the variable in Surefire or Gradle config |
| Gradle test doesn’t rerun | Environment changed outside declared inputs | ./gradlew cleanTest test |
| Compose value is mangled | $ interpolation or YAML quoting | Use $$; single-quote the JSON |
| List binding fails | Wrong JSON structure | Use a JSON array (["a","b"]), which flattens to name[0], name[1] |
A null in JSON has no effect | null is treated as missing | Set an explicit value or an empty string instead |
When Is SPRING_APPLICATION_JSON the Right Tool?
It is a good fit when:
- You deploy to a platform where environment variables are the main configuration channel.
- You need to override a few nested properties without shipping a file.
- Property names contain characters that make env var names awkward.
- You want a one-off override for a manual test, a CI job, or a container.
- You need to override a deployed default without rebuilding the artifact.
A normal application.properties / application.yml is better when:
- The values are the application’s defaults and belong in version control with the code.
- The configuration is large or has comments worth keeping. JSON has no comments.
- You use profiles (
application-test.yml,application-prod.yml). - Many developers need to read and review the configuration.
- The values are static test fixtures. Prefer
@SpringBootTest(properties = ...)or@TestPropertySource.
Rule of thumb: put defaults in files, environment-specific overrides in the environment, and test-specific values in test annotations.
Quick Interview Questions
Is SPRING_APPLICATION_JSON a system property?
No. It is an environment variable. The system-property equivalent is spring.application.json.
Does it override application.properties?
Yes. Config data files are near the bottom of the precedence list, and the JSON sits well above them.
Does it override command-line arguments?
No. Command-line arguments have higher precedence.
Can @TestPropertySource override it?
Yes. Test property sources sit above it.
How do nested JSON objects map to Spring properties?
They are flattened with dots. {"a":{"b":"c"}} becomes a.b=c, and arrays become name[0], name[1].
