GH-2276 - Add support for official IANA HAL media type identifier.
The media type identifier for HAL registered with the IANA is application/vnd.hal+json, notably different from application/hal+json used in the RFC document. This commit adds a constant for that media type identifier and updates the configuration spots necessary to additionally consider it. [0] https://www.iana.org/assignments/media-types/application/vnd.hal+json [1] https://datatracker.ietf.org/doc/html/draft-kelly-json-hal
This commit is contained in:
@@ -19,7 +19,7 @@ import org.springframework.http.MediaType;
|
||||
|
||||
/**
|
||||
* Constants for well-known hypermedia types.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Przemek Nowak
|
||||
* @author Drummond Dawson
|
||||
@@ -37,6 +37,20 @@ public class MediaTypes {
|
||||
*/
|
||||
public static final MediaType HAL_JSON = MediaType.valueOf(HAL_JSON_VALUE);
|
||||
|
||||
/**
|
||||
* A String equivalent of {@link MediaTypes#VND_HAL_JSON}.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
public static final String VND_HAL_JSON_VALUE = "application/vnd.hal+json";
|
||||
|
||||
/**
|
||||
* Public constant media type for {@code application/vnd.hal+json}.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
public static final MediaType VND_HAL_JSON = MediaType.valueOf(VND_HAL_JSON_VALUE);
|
||||
|
||||
/**
|
||||
* A String equivalent of {@link MediaTypes#ALPS_JSON}.
|
||||
*/
|
||||
@@ -76,7 +90,7 @@ public class MediaTypes {
|
||||
* Public constant media type for {@code application/vnd.amundsen-uber+json}.
|
||||
*/
|
||||
public static final MediaType UBER_JSON = MediaType.parseMediaType(UBER_JSON_VALUE);
|
||||
|
||||
|
||||
/**
|
||||
* A String equivalent of {@link MediaTypes#VND_ERROR_JSON}.
|
||||
*/
|
||||
|
||||
@@ -20,13 +20,12 @@ import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.hateoas.support.WebStack;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* Activates hypermedia support in the {@link ApplicationContext}. Will register infrastructure beans to support all
|
||||
@@ -50,8 +49,8 @@ public @interface EnableHypermediaSupport {
|
||||
|
||||
/**
|
||||
* Configures which {@link WebStack}s we're supposed to enable support for. By default we're activating it for all
|
||||
* available ones if they happen to be in use. Configure this explicitly in case you're using WebFlux components
|
||||
* like {@link WebClient} but don't want to use hypermedia operations with it.
|
||||
* available ones if they happen to be in use. Configure this explicitly in case you're using WebFlux components like
|
||||
* {@link WebClient} but don't want to use hypermedia operations with it.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@@ -69,9 +68,9 @@ public @interface EnableHypermediaSupport {
|
||||
* HAL - Hypermedia Application Language.
|
||||
*
|
||||
* @see http://stateless.co/hal_specification.html
|
||||
* @see https://tools.ietf.org/html/draft-kelly-json-hal-05
|
||||
* @see https://tools.ietf.org/html/draft-kelly-json-hal
|
||||
*/
|
||||
HAL(MediaTypes.HAL_JSON, "hal"),
|
||||
HAL(List.of(MediaTypes.HAL_JSON, MediaTypes.VND_HAL_JSON), "hal"),
|
||||
|
||||
/**
|
||||
* HAL-FORMS - Independent, backward-compatible extension of the HAL designed to add runtime FORM support
|
||||
@@ -96,18 +95,33 @@ public @interface EnableHypermediaSupport {
|
||||
*/
|
||||
UBER(MediaTypes.UBER_JSON, "uber");
|
||||
|
||||
private final MediaType mediaTypes;
|
||||
private final List<MediaType> mediaTypes;
|
||||
private final String localPackageName;
|
||||
|
||||
HypermediaType(MediaType mediaType, String localPackageName) {
|
||||
this.mediaTypes = mediaType;
|
||||
this.mediaTypes = List.of(mediaType);
|
||||
this.localPackageName = localPackageName;
|
||||
}
|
||||
|
||||
public MediaType getMediaType() {
|
||||
HypermediaType(List<MediaType> mediaTypes, String localPackageName) {
|
||||
this.mediaTypes = mediaTypes;
|
||||
this.localPackageName = localPackageName;
|
||||
}
|
||||
|
||||
public List<MediaType> getMediaTypes() {
|
||||
return this.mediaTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 2.5, in favor of {@link #getMediaTypes()} as a logical media type might have been associated
|
||||
* with multiple media type identifiers (see {@link #HAL}).
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
@Deprecated(since = "2.5", forRemoval = true)
|
||||
public MediaType getMediaType() {
|
||||
return this.mediaTypes.get(0);
|
||||
}
|
||||
|
||||
public String getLocalPackageName() {
|
||||
return localPackageName;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ class HypermediaConfigurationImportSelector implements ImportSelector, ResourceL
|
||||
List<MediaType> types = attributes == null //
|
||||
? Collections.emptyList() //
|
||||
: Arrays.stream((HypermediaType[]) attributes.get("type")) //
|
||||
.map(it -> it.getMediaType()) //
|
||||
.flatMap(it -> it.getMediaTypes().stream()) //
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!beanFactory.containsBean("hateoasMediaTypeConfigurer")) {
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.hateoas.mediatype.collectionjson;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -48,7 +47,7 @@ class CollectionJsonMediaTypeConfiguration implements HypermediaMappingInformati
|
||||
*/
|
||||
@Override
|
||||
public List<MediaType> getMediaTypes() {
|
||||
return Collections.singletonList(HypermediaType.COLLECTION_JSON.getMediaType());
|
||||
return HypermediaType.COLLECTION_JSON.getMediaTypes();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -16,14 +16,12 @@
|
||||
package org.springframework.hateoas.mediatype.hal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.LinkRelation;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -70,7 +68,7 @@ public class HalConfiguration {
|
||||
public HalConfiguration() {
|
||||
|
||||
this(RenderSingleLinks.AS_SINGLE, new LinkedHashMap<>(), true, true, __ -> {},
|
||||
Collections.singletonList(MediaTypes.HAL_JSON));
|
||||
List.of(MediaTypes.HAL_JSON, MediaTypes.VND_HAL_JSON));
|
||||
}
|
||||
|
||||
private HalConfiguration(RenderSingleLinks renderSingleLinks, Map<String, RenderSingleLinks> singleLinksPerPattern,
|
||||
|
||||
@@ -21,7 +21,6 @@ import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.LinkRelation;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.hateoas.client.JsonPathLinkDiscoverer;
|
||||
import org.springframework.hateoas.client.LinkDiscoverer;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
/**
|
||||
@@ -36,7 +35,7 @@ public class HalLinkDiscoverer extends JsonPathLinkDiscoverer {
|
||||
* Constructor for {@link MediaTypes#HAL_JSON}.
|
||||
*/
|
||||
public HalLinkDiscoverer() {
|
||||
this(MediaTypes.HAL_JSON);
|
||||
this(MediaTypes.HAL_JSON, MediaTypes.VND_HAL_JSON);
|
||||
}
|
||||
|
||||
protected HalLinkDiscoverer(MediaType... mediaTypes) {
|
||||
|
||||
@@ -44,6 +44,8 @@ class HalMediaTypeConfigurationProvider implements MediaTypeConfigurationProvide
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsAny(Collection<MediaType> mediaTypes) {
|
||||
return mediaTypes.contains(MediaTypes.HAL_JSON);
|
||||
|
||||
return mediaTypes.contains(MediaTypes.HAL_JSON)
|
||||
|| mediaTypes.contains(MediaTypes.VND_HAL_JSON);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
*/
|
||||
class HalTraversonDefaults implements TraversonDefaults {
|
||||
|
||||
private static final List<MediaType> HAL_FLAVORS = Collections.singletonList(MediaTypes.HAL_JSON);
|
||||
private static final List<MediaType> HAL_FLAVORS = List.of(MediaTypes.HAL_JSON, MediaTypes.VND_HAL_JSON,
|
||||
MediaTypes.HAL_FORMS_JSON);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -70,8 +71,8 @@ class HalTraversonDefaults implements TraversonDefaults {
|
||||
@Override
|
||||
public List<LinkDiscoverer> getLinkDiscoverers(Collection<MediaType> mediaTypes) {
|
||||
|
||||
return mediaTypes.stream().anyMatch(it -> it.isCompatibleWith(MediaTypes.HAL_JSON)) //
|
||||
? Collections.singletonList(new HalLinkDiscoverer()) //
|
||||
return mediaTypes.stream().anyMatch(it -> HAL_FLAVORS.stream().anyMatch(it::isCompatibleWith)) //
|
||||
? List.of(new HalLinkDiscoverer()) //
|
||||
: Collections.emptyList();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.hateoas.mediatype.uber;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -48,7 +47,7 @@ class UberMediaTypeConfiguration implements HypermediaMappingInformation {
|
||||
*/
|
||||
@Override
|
||||
public List<MediaType> getMediaTypes() {
|
||||
return Collections.singletonList(HypermediaType.UBER.getMediaType());
|
||||
return HypermediaType.UBER.getMediaTypes();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -110,6 +110,8 @@ class EnableHypermediaSupportIntegrationTest {
|
||||
assertThat(discoverers).isNotNull();
|
||||
assertThat(discoverers.getLinkDiscovererFor(MediaTypes.HAL_JSON))
|
||||
.hasValueSatisfying(HalLinkDiscoverer.class::isInstance);
|
||||
assertThat(discoverers.getLinkDiscovererFor(MediaTypes.VND_HAL_JSON))
|
||||
.hasValueSatisfying(HalLinkDiscoverer.class::isInstance);
|
||||
assertRelProvidersSetUp(context);
|
||||
});
|
||||
}
|
||||
@@ -138,6 +140,8 @@ class EnableHypermediaSupportIntegrationTest {
|
||||
assertThat(discoverers).isNotNull();
|
||||
assertThat(discoverers.getLinkDiscovererFor(MediaTypes.HAL_JSON))
|
||||
.hasValueSatisfying(HalLinkDiscoverer.class::isInstance);
|
||||
assertThat(discoverers.getLinkDiscovererFor(MediaTypes.VND_HAL_JSON))
|
||||
.hasValueSatisfying(HalLinkDiscoverer.class::isInstance);
|
||||
|
||||
assertThat(discoverers.getLinkDiscovererFor(MediaTypes.HAL_FORMS_JSON))
|
||||
.hasValueSatisfying(HalFormsLinkDiscoverer.class::isInstance);
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
|
||||
import org.springframework.hateoas.config.RestTemplateHateoasConfiguration.HypermediaRestTemplateBeanPostProcessor;
|
||||
import org.springframework.hateoas.support.CustomHypermediaType;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
@@ -55,6 +54,7 @@ class HypermediaRestTemplateBeanPostProcessorTest {
|
||||
assertThat(getSupportedHypermediaTypes(context, REST_TEMPLATE_EXTRACTOR)) //
|
||||
.containsExactlyInAnyOrder( //
|
||||
MediaTypes.HAL_JSON, //
|
||||
MediaTypes.VND_HAL_JSON, //
|
||||
MediaType.APPLICATION_JSON, //
|
||||
MediaType.parseMediaType("application/*+json"));
|
||||
});
|
||||
@@ -71,6 +71,7 @@ class HypermediaRestTemplateBeanPostProcessorTest {
|
||||
assertThat(getSupportedHypermediaTypes(context, REST_TEMPLATE_EXTRACTOR)) //
|
||||
.containsExactlyInAnyOrder( //
|
||||
MediaTypes.HAL_JSON, //
|
||||
MediaTypes.VND_HAL_JSON, //
|
||||
MediaTypes.COLLECTION_JSON, //
|
||||
MediaType.APPLICATION_JSON, //
|
||||
MediaType.parseMediaType("application/*+json"));
|
||||
@@ -88,6 +89,7 @@ class HypermediaRestTemplateBeanPostProcessorTest {
|
||||
assertThat(getSupportedHypermediaTypes(context, REST_TEMPLATE_EXTRACTOR)) //
|
||||
.containsExactlyInAnyOrder( //
|
||||
MediaTypes.HAL_JSON, //
|
||||
MediaTypes.VND_HAL_JSON, //
|
||||
MediaTypes.HAL_FORMS_JSON, //
|
||||
MediaTypes.COLLECTION_JSON, //
|
||||
MediaTypes.UBER_JSON, //
|
||||
@@ -104,6 +106,7 @@ class HypermediaRestTemplateBeanPostProcessorTest {
|
||||
assertThat(getSupportedHypermediaTypes(context, REST_TEMPLATE_EXTRACTOR)) //
|
||||
.containsExactlyInAnyOrder( //
|
||||
MediaTypes.HAL_JSON, //
|
||||
MediaTypes.VND_HAL_JSON, //
|
||||
MediaType.parseMediaType("application/frodo+json"), //
|
||||
MediaType.APPLICATION_JSON, //
|
||||
MediaType.parseMediaType("application/*+json") //
|
||||
|
||||
Reference in New Issue
Block a user