From 192764d2ea0b1a5581147e45414cefc02e67d025 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Wed, 4 Jun 2025 19:25:43 +0200 Subject: [PATCH] GH-2333 - Fix custom media type registration in HalConfiguration. With the addition of the vnd.hal+json media type, our registration of custom media types ordered these behind the legacy hal+json media type. We now try to find the first of the default media types and insert custom ones right before that one. --- .../hateoas/mediatype/hal/HalConfiguration.java | 8 +++++--- .../mediatype/hal/HalConfigurationUnitTest.java | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/springframework/hateoas/mediatype/hal/HalConfiguration.java b/src/main/java/org/springframework/hateoas/mediatype/hal/HalConfiguration.java index 1063fcfe..70dc0d37 100644 --- a/src/main/java/org/springframework/hateoas/mediatype/hal/HalConfiguration.java +++ b/src/main/java/org/springframework/hateoas/mediatype/hal/HalConfiguration.java @@ -40,6 +40,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; public class HalConfiguration { private static final PathMatcher MATCHER = new AntPathMatcher(); + private static final List DEFAULT_MEDIA_TYPES = List.of(MediaTypes.HAL_JSON, MediaTypes.VND_HAL_JSON); /** * Configures how to render links in case there is exactly one defined for a given link relation in general. By @@ -67,8 +68,7 @@ public class HalConfiguration { */ public HalConfiguration() { - this(RenderSingleLinks.AS_SINGLE, new LinkedHashMap<>(), true, true, __ -> {}, - List.of(MediaTypes.HAL_JSON, MediaTypes.VND_HAL_JSON)); + this(RenderSingleLinks.AS_SINGLE, new LinkedHashMap<>(), true, true, __ -> {}, DEFAULT_MEDIA_TYPES); } private HalConfiguration(RenderSingleLinks renderSingleLinks, Map singleLinksPerPattern, @@ -233,8 +233,10 @@ public class HalConfiguration { return this; } + var index = mediaTypes.indexOf(DEFAULT_MEDIA_TYPES.get(0)); + List newMediaTypes = new ArrayList<>(mediaTypes); - newMediaTypes.add(mediaTypes.size() - 1, mediaType); + newMediaTypes.add(index, mediaType); return new HalConfiguration(renderSingleLinks, singleLinksPerPattern, applyPropertyNamingStrategy, enforceEmbeddedCollections, objectMapperCustomizer, newMediaTypes); diff --git a/src/test/java/org/springframework/hateoas/mediatype/hal/HalConfigurationUnitTest.java b/src/test/java/org/springframework/hateoas/mediatype/hal/HalConfigurationUnitTest.java index 81773df4..65c89d25 100644 --- a/src/test/java/org/springframework/hateoas/mediatype/hal/HalConfigurationUnitTest.java +++ b/src/test/java/org/springframework/hateoas/mediatype/hal/HalConfigurationUnitTest.java @@ -19,7 +19,9 @@ import static org.assertj.core.api.Assertions.*; import org.junit.jupiter.api.Test; import org.springframework.hateoas.LinkRelation; +import org.springframework.hateoas.MediaTypes; import org.springframework.hateoas.mediatype.hal.HalConfiguration.RenderSingleLinks; +import org.springframework.http.MediaType; /** * Unit tests for {@link HalConfiguration}. @@ -65,4 +67,18 @@ class HalConfigurationUnitTest { assertThat(configuration.getSingleLinkRenderModeFor(LinkRelation.of("https://somehost/bar"))) .isEqualTo(RenderSingleLinks.AS_SINGLE); } + + @Test // GH-2333 + void registersCustomMediaTypesFirst() { + + var config = new HalConfiguration() + .withMediaType(MediaType.APPLICATION_CBOR) + .withMediaType(MediaType.APPLICATION_PDF); + + assertThat(config.getMediaTypes()).containsExactly( + MediaType.APPLICATION_CBOR, + MediaType.APPLICATION_PDF, + MediaTypes.HAL_JSON, + MediaTypes.VND_HAL_JSON); + } }