skip to content

What is Spring's MessageSource, and how do you use getMessage to resolve a localized message with arguments?

level: juniorimportance: must knowfreq 55%

answer

  1. code + args + Locale
  2. {0} = MessageFormat placeholder
  3. bean must be named messageSource
  4. 3 overloads: default / throws / Resolvable
  5. messages_fr.properties fallback chain

basics

~20 s

MessageSource is Spring's interface for resolving text by a code for a given Locale. You call getMessage(code, args, locale); args fill placeholders like {0} in the properties file, so one code renders in different languages.

solid answer

~30 s

MessageSource is Spring's abstraction for internationalized (i18n) text lookup. You resolve a message by a String code, passing an Object[] of arguments and a java.util.Locale; Spring finds the matching properties file (e.g. messages_fr.properties) and substitutes arguments into MessageFormat placeholders {0}, {1}. Three overloads exist: one taking a defaultMessage (returned on a miss), one that throws NoSuchMessageException on a miss, and one taking a MessageSourceResolvable. The ApplicationContext itself implements MessageSource, delegating to a bean that must be named exactly 'messageSource'. In Spring Boot a ResourceBundleMessageSource over the 'messages' basename is auto-configured, so you add messages.properties files per locale and inject MessageSource.

code

java · 22 lines
java
@Configuration
public class I18nConfig {
    @Bean
    public MessageSource messageSource() {
        var ms = new ResourceBundleMessageSource();
        ms.setBasename("messages");           // messages.properties, messages_fr.properties...
        ms.setDefaultEncoding("UTF-8");
        return ms;
    }
}

@Service
public class Greeter {
    private final MessageSource messages;
    public Greeter(MessageSource messages) { this.messages = messages; }

    public String greet(String name, Locale locale) {
        // messages.properties:    greeting=Hello, {0}!
        // messages_fr.properties: greeting=Bonjour, {0} !
        return messages.getMessage("greeting", new Object[]{name}, locale);
    }
}

go deeper

for a junior

Knows getMessage(code, args, locale) and per-locale properties files.

for a middle

Understands the three overloads, the fallback chain, and the messageSource bean-name requirement.

for a senior

Explains MessageFormat quoting, default-message vs exception semantics, and Boot auto-configuration.

for a principal

Frames i18n as an externalization/ops concern; standardizes codes, encoding, and missing-key policy across services.

**What it is.** `org.springframework.context.MessageSource` is Spring's core interface for *internationalization* (i18n) — resolving human-readable text by a symbolic **code** instead of hard-coding strings, so one application can render French, German, etc. based on a **Locale** (`java.util.Locale`). **The three getMessage overloads:** - `getMessage(String code, Object[] args, String defaultMessage, Locale locale)` — returns `defaultMessage` (may be `null`) if the code is not found; never throws. - `getMessage(String code, Object[] args, Locale locale)` — throws `NoSuchMessageException` if the code is missing. - `getMessage(MessageSourceResolvable resolvable, Locale locale)` — resolves an object that carries its own codes/args/default (used by validation errors). **How lookup works.** Messages live in `.properties` files keyed by a **basename** plus a locale suffix: `messages.properties` (default), `messages_fr.properties`, `messages_fr_FR.properties`. For `Locale.FRANCE` Spring tries the most specific file first (`_fr_FR`), then `_fr`, then the base file. Each file holds `code=text` pairs, e.g. `greeting=Hello, {0}!`. **Arguments and placeholders.** When you pass a non-empty `args` array, Spring runs the text through `java.text.MessageFormat`. `{0}` is replaced by `args[0]`, `{1}` by `args[1]`, and typed formats like `{0,number,currency}` or `{0,date,long}` are supported. Gotcha: with args present, a literal single quote must be **doubled** (`''`) because `MessageFormat` treats `'` as an escape. **Wiring.** The `ApplicationContext` *is* a `MessageSource` — but it only works if you register a bean literally named **`messageSource`**; `AbstractApplicationContext` looks that bean up by name during refresh. In Spring Boot, `MessageSourceAutoConfiguration` creates a `ResourceBundleMessageSource` from the `messages` basename automatically (configurable via `spring.messages.*`). You then inject either the `MessageSource` bean or the `ApplicationContext`. **When to use.** Any user-facing text that must vary by language or that you want centralized/externalized: validation messages, emails, UI labels, error responses.

  • What happens if the code isn't found?
    The overload with a defaultMessage returns that default (or null); the overload without one throws NoSuchMessageException. You can also set useCodeAsDefaultMessage=true to return the code itself instead of throwing.
  • Why must the bean be named 'messageSource'?
    AbstractApplicationContext.initMessageSource() looks up a bean by that exact name to back the context's own MessageSource; a differently-named bean is ignored and a DelegatingMessageSource with no parent is used, so lookups fail.

saying these in an interview costs you the question

  • Thinking getMessage always throws when a code is missing (the defaultMessage overload doesn't)
  • Naming the bean anything other than 'messageSource' and expecting it to work
  • Forgetting that placeholders use MessageFormat {0} indexing, not named tokens

context