HttpHeaders::setAcceptLanguageAsLocales makes header lowercase

Viewed 88

When I use setAcceptLanguageAsLocales, header content is all lowercase

HttpHeaders headers = new HttpHeaders();
headers.setAcceptLanguageAsLocales(List.of(Locale.US, Locale.GERMANY));

Result:

Accept-Language: en-us, de-de

Why it is converted to lowercase? I would expect:

Accept-Language: en-US, de-DE
1 Answers

That is the consequence of Spring Framework code. If you check HttpHeaders code, you will find that the implementation of the method setAcceptLanguageAsLocales is as follows:

public void setAcceptLanguageAsLocales(List<Locale> locales) {
  setAcceptLanguage(locales.stream()
      .map(locale -> new Locale.LanguageRange(locale.toLanguageTag()))
      .collect(Collectors.toList()));
}

The important part is the conversion to a Locale.LanguageRange object. If you inspect its code, you will find that its LanguageRange(String range, double weight) constructor is implemented as follows:

public LanguageRange(String range, double weight) {
    if (range == null) {
        throw new NullPointerException();
    }
    if (weight < MIN_WEIGHT || weight > MAX_WEIGHT) {
        throw new IllegalArgumentException("weight=" + weight);
    }

    range = range.toLowerCase(Locale.ROOT);

    // Do syntax check.
    boolean isIllFormed = false;
    String[] subtags = range.split("-");
    if (isSubtagIllFormed(subtags[0], true)
        || range.endsWith("-")) {
        isIllFormed = true;
    } else {
        for (int i = 1; i < subtags.length; i++) {
            if (isSubtagIllFormed(subtags[i], false)) {
                isIllFormed = true;
                break;
            }
        }
    }
    if (isIllFormed) {
        throw new IllegalArgumentException("range=" + range);
    }

    this.range = range;
    this.weight = weight;
}

The important part is the line range = range.toLowerCase(Locale.ROOT); that actually converts everything in the provided locale.toLanguageTag() to lowercase, hence the result that you observed. The code below mimics Spring Framework code and will show you the results:

public class Main {
    public static void main(String[] args) {
        List<Locale> locales = List.of(Locale.US, Locale.GERMANY);
        System.out.println("::::: Original Locales :::::");
        System.out.println(locales);

        System.out.println("::::: Language Tags :::::");
        List<Locale.LanguageRange> languages = locales.stream()
                .map(locale -> {
                    String languageTag = locale.toLanguageTag();
                    System.out.println(languageTag);

                    return new Locale.LanguageRange(languageTag);
                })
                .collect(Collectors.toList());
        System.out.println("::::: Locales Language Rages :::::");
        System.out.println(languages);
    }
}
Related