skip to content

What is Spring's Resource interface, and what are its common implementations?

level: juniorimportance: must knowfreq 55%

answer

  1. InputStreamSource -> getInputStream()
  2. ClassPath / FileSystem / Url + ByteArray / InputStream
  3. getFile() throws for classpath-in-JAR
  4. unifies File + URL + InputStream
  5. usually created by a ResourceLoader, not by hand

basics

~10 s

Resource is Spring's abstraction for a readable low-level resource (a file, classpath entry, or URL). Common implementations are ClassPathResource, FileSystemResource, and UrlResource. You mainly call getInputStream(), exists(), and getFilename().

solid answer

~40 s

org.springframework.core.io.Resource is Spring's unified handle to any low-level external resource, hiding whether it lives on the classpath, filesystem, or a URL. It extends InputStreamSource, so the core method is getInputStream(); it also offers exists(), isReadable(), getURL(), getFile(), and getFilename(). The main implementations are ClassPathResource (loaded from the classpath), FileSystemResource / PathResource (filesystem paths), UrlResource (any java.net.URL: http, ftp, file), plus ByteArrayResource and InputStreamResource for in-memory data. The value is a single type you can pass around instead of juggling File, URL, and InputStream. It's better than java.net.URL because it can also point at classpath entries and gives richer metadata (existence, description). You rarely construct these by hand — a ResourceLoader creates the right implementation from a location string.

code

java · 17 lines
java
import org.springframework.core.io.Resource;
import org.springframework.core.io.ClassPathResource;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

public class ResourceDemo {
    public String readSeed() throws Exception {
        Resource seed = new ClassPathResource("data/seed.json");
        if (!seed.exists()) {
            throw new IllegalStateException("missing: " + seed.getDescription());
        }
        // getInputStream() works whether the file is on disk or inside a JAR.
        try (InputStream in = seed.getInputStream()) {
            return new String(in.readAllBytes(), StandardCharsets.UTF_8);
        }
    }
}

go deeper

for a junior

Should name Resource as an abstraction over files/classpath/URLs and mention getInputStream() and the three main implementations.

for a middle

Should explain the getFile() vs getInputStream() JAR gotcha and know ByteArray/InputStream variants.

for a senior

Should discuss single-read InputStreamResource, createRelative(), and choosing Resource for portable content loading.

for a principal

Frames Resource as the SPI that lets the whole context bootstrap uniformly across exploded, JAR, and remote deployments.

## What it is `org.springframework.core.io.Resource` is Spring's abstraction over any *low-level* resource you might want to read: a file on disk, an entry inside a JAR on the classpath, a byte array in memory, or something at an HTTP/FTP URL. Before Spring, Java forced you to choose between `java.io.File` (filesystem only), `java.net.URL` (network-ish, awkward for classpath), and raw `InputStream` (no metadata). `Resource` unifies all of these behind one interface so application code doesn't care *where* the bytes come from. ## The interface `Resource extends InputStreamSource`. `InputStreamSource` declares the single most important method: - `InputStream getInputStream()` — open a **fresh** stream each call; the caller must close it. `Resource` adds metadata/capability methods: - `boolean exists()` — does the resource physically exist? - `boolean isReadable()` — exists and its content is readable. - `boolean isOpen()` — true only for already-open streams (e.g. `InputStreamResource`) that can be read once. - `URL getURL()` / `URI getURI()` — resolve to a URL/URI if possible. - `File getFile()` — resolve to a `java.io.File`; **throws `FileNotFoundException` if the resource can't be resolved to the filesystem** (e.g. a classpath entry inside a JAR). - `long contentLength()`, `long lastModified()`. - `Resource createRelative(String relativePath)` — resolve a path relative to this resource. - `String getFilename()` — the last path segment, or null. - `String getDescription()` — a human-readable description used in error messages. ## Key implementations - **`ClassPathResource`** — reads from the classpath via a `ClassLoader` (or `Class`). Handles entries inside JARs. `getFile()` fails if the entry is nested in a JAR (there's no real file). - **`FileSystemResource`** — a path on the filesystem, backed by `java.io.File`/`java.nio.file.Path`. - **`PathResource`** — NIO `Path`-based filesystem resource (supports NIO-only filesystems). - **`UrlResource`** — wraps a `java.net.URL`; supports `http:`, `https:`, `ftp:`, `file:`, and even `jar:`/`war:` URLs. - **`ByteArrayResource`** — reads from an in-memory `byte[]`; re-readable. - **`InputStreamResource`** — wraps an existing `InputStream`; `isOpen()` returns true and it can only be read **once** — use only when no better implementation fits. - **`ServletContextResource`** — reads relative to a web application root (`ServletContext`). ## When to use Use `Resource` any time you inject or load external content — templates, SQL scripts, config files, keystores, seed data. In Spring you can even `@Value("classpath:data/seed.json") Resource seed;` and Spring converts the string to the right implementation for you. ## Gotchas - `getInputStream()` returns a fresh stream you must close; use try-with-resources. - `getFile()` throws for classpath-in-JAR resources — prefer `getInputStream()` for portable code that must work both from an IDE (exploded classes) and a packaged JAR. - `InputStreamResource` is single-read; don't reuse it. - `exists()` doesn't guarantee readability; use `isReadable()` when you actually plan to open it.

  • Why prefer getInputStream() over getFile() when reading a classpath resource?
    getFile() resolves to a java.io.File and throws FileNotFoundException when the resource lives inside a JAR (no real file exists). getInputStream() works in both exploded (IDE) and packaged-JAR deployments, so it's the portable choice.
  • What's special about InputStreamResource compared to ByteArrayResource?
    InputStreamResource wraps an already-open stream, so isOpen() is true and it can only be read once. ByteArrayResource holds an in-memory byte[] and is re-readable. Prefer ByteArrayResource (or another concrete type) unless you truly only have a raw stream.

saying these in an interview costs you the question

  • Claiming getFile() always works for classpath resources (fails inside a JAR).
  • Thinking Resource is just a wrapper around java.io.File (it also covers classpath and URLs).
  • Assuming you can read an InputStreamResource multiple times.

context