AcceptHeaderNegotiator implements ContentNegotiator { @Override public String bestAllowedLanguage(String acceptsHeader, Set<String> available) { Map<String, Double> accepts = Arrays .stream(ACCEPTS_DELIMITER.split(acceptsHeader)) .map(accept -> parseAcceptFragment(accept, String.class)) .filter(Objects::nonNull) .collect(Collectors.toMap( AcceptFragment::getFragment, AcceptFragment::getQ)); Function<String, Double> score = langtag -> { for (String x = langtag; x != null; x = x.substring(0, x.lastIndexOf('-'))) { Double q = accepts.get(x); if (q != null) return q; if (!x.contains("-")) break; } return Objects.equals(langtag, "*") ? 0.01 : 0; }; return selectBest(available, score).orElse(null); }  double parseQ(String qstr); AcceptFragment<S> parseAcceptFragment(String accept, Class<? extends S> acceptType); @Override MediaType bestAllowedContentType(String acceptsHeader, Set<String> allowedTypes); @Override String bestAllowedCharset(String acceptsHeader, Set<String> available); @Override String bestAllowedEncoding(String acceptsHeader, Set<String> available); @Override String bestAllowedLanguage(String acceptsHeader, Set<String> available);  }
@Test void acceptLanguage() { Set<String> allowedLangs = new HashSet<>(Arrays.asList("da", "en-gb", "en")); assertThat(neg.bestAllowedLanguage("da, en-gb;q=0.8, en; q=0.7", allowedLangs)) .isEqualTo("da"); allowedLangs = new HashSet<>(Arrays.asList("en-gb", "en")); assertThat(neg.bestAllowedLanguage("da, en-gb;q=0.8, en; q=0.7", allowedLangs)) .isEqualTo("en-gb"); allowedLangs = new HashSet<>(Collections.singletonList("en")); assertThat(neg.bestAllowedLanguage("da, en-gb;q=0.8, en; q=0.7", allowedLangs)) .isEqualTo("en"); allowedLangs = new HashSet<>(Collections.singletonList("en-cockney")); assertThat(neg.bestAllowedLanguage("da, en-gb;q=0.8", allowedLangs)) .isNull(); }