Spring Boot
JSON
data loading
application development
Java

Best way to load some JSON files into a Spring Boot application

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

The best way to load JSON files in a Spring Boot application depends on what those files represent. If they are application configuration, bind them into typed properties. If they are business data, fixtures, or seed content, load them as resources and deserialize them with Jackson. The mistake is treating every JSON file like generic text instead of deciding whether it belongs to configuration, startup data, or request-time input.

Choose the Loading Strategy by Use Case

These are the most common cases:

  • configuration-like values used during startup
  • static JSON resources bundled inside the application
  • external JSON files mounted or supplied at runtime

Once you classify the file, the loading pattern becomes much clearer.

Loading Classpath JSON With Resource

For bundled JSON files under src/main/resources, Spring's Resource abstraction plus Jackson is usually the cleanest approach.

Assume a file at src/main/resources/data/countries.json:

json
1[
2  { "code": "CA", "name": "Canada" },
3  { "code": "US", "name": "United States" }
4]

Java model:

java
1package com.example.demo;
2
3public record Country(String code, String name) {
4}

Loader service:

java
1package com.example.demo;
2
3import com.fasterxml.jackson.core.type.TypeReference;
4import com.fasterxml.jackson.databind.ObjectMapper;
5import org.springframework.core.io.ClassPathResource;
6import org.springframework.stereotype.Service;
7
8import java.io.IOException;
9import java.io.InputStream;
10import java.util.List;
11
12@Service
13public class CountryLoader {
14
15    private final ObjectMapper objectMapper;
16
17    public CountryLoader(ObjectMapper objectMapper) {
18        this.objectMapper = objectMapper;
19    }
20
21    public List<Country> loadCountries() throws IOException {
22        ClassPathResource resource = new ClassPathResource("data/countries.json");
23        try (InputStream inputStream = resource.getInputStream()) {
24            return objectMapper.readValue(inputStream, new TypeReference<List<Country>>() {});
25        }
26    }
27}

This is a good default because it is typed, testable, and works the same from the IDE and from the packaged jar.

Loading Data at Startup

If the JSON should be read once on application startup, use ApplicationRunner or CommandLineRunner rather than scattering file reads across controllers.

java
1package com.example.demo;
2
3import org.springframework.boot.ApplicationRunner;
4import org.springframework.context.annotation.Bean;
5import org.springframework.context.annotation.Configuration;
6
7@Configuration
8public class StartupConfig {
9
10    @Bean
11    ApplicationRunner loadReferenceData(CountryLoader loader) {
12        return args -> {
13            var countries = loader.loadCountries();
14            System.out.println("Loaded countries: " + countries.size());
15        };
16    }
17}

This makes startup behavior explicit and keeps file loading out of request paths unless you truly need dynamic reload behavior.

When the JSON Is External

If operations teams need to replace the file without rebuilding the jar, do not keep it only on the classpath. Point to an external location through configuration:

yaml
app:
  country-file: /opt/app/config/countries.json

Then inject the path:

java
1package com.example.demo;
2
3import com.fasterxml.jackson.core.type.TypeReference;
4import com.fasterxml.jackson.databind.ObjectMapper;
5import org.springframework.beans.factory.annotation.Value;
6import org.springframework.stereotype.Service;
7
8import java.io.IOException;
9import java.nio.file.Files;
10import java.nio.file.Path;
11import java.util.List;
12
13@Service
14public class ExternalCountryLoader {
15
16    private final ObjectMapper objectMapper;
17    private final Path path;
18
19    public ExternalCountryLoader(
20        ObjectMapper objectMapper,
21        @Value("${app.country-file}") String filePath
22    ) {
23        this.objectMapper = objectMapper;
24        this.path = Path.of(filePath);
25    }
26
27    public List<Country> loadCountries() throws IOException {
28        try (var reader = Files.newBufferedReader(path)) {
29            return objectMapper.readValue(reader, new TypeReference<List<Country>>() {});
30        }
31    }
32}

This is more flexible for deployment-specific data.

Avoid Treating JSON as a Generic String Blob

A weak pattern is to read the file into a String and pass raw JSON around the application. That loses type safety and pushes parsing errors further downstream. Deserialize at the boundary instead and keep the rest of the code working with normal Java objects.

If the file contents are truly dynamic and schema-free, use JsonNode rather than raw strings so you still get structured access.

Common Pitfalls

  • Using application.properties or application.yaml to embed large business-data JSON blobs.
  • Reading classpath files with plain filesystem paths, which often breaks once the app is packaged.
  • Parsing JSON late and passing raw text through service layers.
  • Loading reference files on every request instead of at startup or through a cache.
  • Choosing classpath storage when operations actually need runtime-replaceable external files.

Summary

  • Pick the loading strategy based on whether the JSON is configuration, bundled data, or external runtime data.
  • For bundled files, use Spring Resource APIs and Jackson deserialization.
  • For startup-only loading, centralize the read in an ApplicationRunner or similar boot hook.
  • For runtime-managed files, inject an external path through configuration.
  • Deserialize into typed objects early so the rest of the application stays simple.

Course illustration
Course illustration

All Rights Reserved.