#1591 - Support for custom media type aliases in HAL FORMS.
This commit is contained in:
@@ -15,7 +15,10 @@
|
||||
*/
|
||||
package org.springframework.hateoas.mediatype.hal.forms;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
@@ -23,7 +26,9 @@ import java.util.function.Function;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.hateoas.AffordanceModel.PropertyMetadata;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.hateoas.mediatype.hal.HalConfiguration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -41,6 +46,7 @@ public class HalFormsConfiguration {
|
||||
private final Map<Class<?>, String> patterns;
|
||||
private final Consumer<ObjectMapper> objectMapperCustomizer;
|
||||
private final HalFormsOptionsFactory options;
|
||||
private final List<MediaType> mediaTypes;
|
||||
|
||||
/**
|
||||
* Creates a new {@link HalFormsConfiguration} backed by a default {@link HalConfiguration}.
|
||||
@@ -55,21 +61,25 @@ public class HalFormsConfiguration {
|
||||
* @param halConfiguration must not be {@literal null}.
|
||||
*/
|
||||
public HalFormsConfiguration(HalConfiguration halConfiguration) {
|
||||
this(halConfiguration, new HashMap<>(), new HalFormsOptionsFactory(), __ -> {});
|
||||
this(halConfiguration, new HashMap<>(), new HalFormsOptionsFactory(), __ -> {},
|
||||
Collections.singletonList(MediaTypes.HAL_FORMS_JSON));
|
||||
}
|
||||
|
||||
private HalFormsConfiguration(HalConfiguration halConfiguration, Map<Class<?>, String> patterns,
|
||||
HalFormsOptionsFactory options, @Nullable Consumer<ObjectMapper> objectMapperCustomizer) {
|
||||
HalFormsOptionsFactory options, @Nullable Consumer<ObjectMapper> objectMapperCustomizer,
|
||||
List<MediaType> mediaTypes) {
|
||||
|
||||
Assert.notNull(halConfiguration, "HalConfiguration must not be null!");
|
||||
Assert.notNull(patterns, "Patterns must not be null!");
|
||||
Assert.notNull(objectMapperCustomizer, "ObjectMapper customizer must not be null!");
|
||||
Assert.notNull(options, "HalFormsSuggests must not be null!");
|
||||
Assert.notNull(mediaTypes, "Media types must not be null!");
|
||||
|
||||
this.halConfiguration = halConfiguration;
|
||||
this.patterns = patterns;
|
||||
this.objectMapperCustomizer = objectMapperCustomizer;
|
||||
this.options = options;
|
||||
this.mediaTypes = new ArrayList<>(mediaTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,7 +116,7 @@ public class HalFormsConfiguration {
|
||||
Map<Class<?>, String> newPatterns = new HashMap<>(patterns);
|
||||
newPatterns.put(type, pattern);
|
||||
|
||||
return new HalFormsConfiguration(halConfiguration, newPatterns, options, objectMapperCustomizer);
|
||||
return new HalFormsConfiguration(halConfiguration, newPatterns, options, objectMapperCustomizer, mediaTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,7 +132,30 @@ public class HalFormsConfiguration {
|
||||
|
||||
return this.objectMapperCustomizer == objectMapperCustomizer //
|
||||
? this //
|
||||
: new HalFormsConfiguration(halConfiguration, patterns, options, objectMapperCustomizer);
|
||||
: new HalFormsConfiguration(halConfiguration, patterns, options, objectMapperCustomizer, mediaTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional media types that are supposed to be aliases to {@link MediaTypes#HAL_FORMS_JSON}. Registered
|
||||
* {@link MediaType}s will be preferred over the default one, i.e. they'll be listed first in client's accept headers
|
||||
* etc.
|
||||
*
|
||||
* @param mediaType must not be {@literal null}.
|
||||
* @return will never be {@literal null}.
|
||||
* @since 1.4
|
||||
*/
|
||||
public HalFormsConfiguration withMediaType(MediaType mediaType) {
|
||||
|
||||
Assert.notNull(mediaType, "MediaType must not be null!");
|
||||
|
||||
if (mediaTypes.contains(mediaType)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
List<MediaType> newMediaTypes = new ArrayList<>(mediaTypes);
|
||||
newMediaTypes.add(mediaTypes.size() - 1, mediaType);
|
||||
|
||||
return new HalFormsConfiguration(halConfiguration, patterns, options, objectMapperCustomizer, newMediaTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,7 +187,7 @@ public class HalFormsConfiguration {
|
||||
Function<PropertyMetadata, HalFormsOptions> creator) {
|
||||
|
||||
return new HalFormsConfiguration(halConfiguration, patterns, options.withOptions(type, property, creator),
|
||||
objectMapperCustomizer);
|
||||
objectMapperCustomizer, mediaTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,9 +212,18 @@ public class HalFormsConfiguration {
|
||||
* Returns the regular expression pattern that is registered for the given type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
Optional<String> getTypePatternFor(ResolvableType type) {
|
||||
return Optional.ofNullable(patterns.get(type.resolve(Object.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link MediaType}s that we want to register this configuration for.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
List<MediaType> getMediaTypes() {
|
||||
return Collections.unmodifiableList(mediaTypes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFact
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.hateoas.client.LinkDiscoverer;
|
||||
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
|
||||
import org.springframework.hateoas.config.HypermediaMappingInformation;
|
||||
import org.springframework.hateoas.mediatype.MessageResolver;
|
||||
import org.springframework.hateoas.mediatype.hal.CurieProvider;
|
||||
@@ -106,7 +105,7 @@ class HalFormsMediaTypeConfiguration implements HypermediaMappingInformation {
|
||||
*/
|
||||
@Override
|
||||
public List<MediaType> getMediaTypes() {
|
||||
return HypermediaType.HAL_FORMS.getMediaTypes();
|
||||
return getResolvedConfiguration().getMediaTypes();
|
||||
}
|
||||
|
||||
HalFormsConfiguration getResolvedConfiguration() {
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas.mediatype.hal.forms;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.hateoas.support.ContextTester.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.hateoas.config.EnableHypermediaSupport;
|
||||
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
|
||||
import org.springframework.hateoas.mediatype.MediaTypeTestUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
/**
|
||||
* Integration tests for HAL media type configuration.
|
||||
*
|
||||
* @author Oliver Drotbohm
|
||||
*/
|
||||
class HalFormsMediaTypeConfigurationIntegrationTest {
|
||||
|
||||
static final MediaType CUSTOM_MEDIA_TYPE = MediaType.parseMediaType("application/vnd.my-custom-mediatype");
|
||||
|
||||
@Test // #1591
|
||||
void includesCustomMediaTypeFromConfiguration() {
|
||||
|
||||
withServletContext(ConfigurationWithCustomMediaType.class, it -> {
|
||||
assertThat(MediaTypeTestUtils.getSupportedHypermediaTypes(it)).contains(CUSTOM_MEDIA_TYPE);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@EnableHypermediaSupport(type = HypermediaType.HAL_FORMS)
|
||||
static class ConfigurationWithCustomMediaType {
|
||||
|
||||
@Bean
|
||||
HalFormsConfiguration halConfiguration() {
|
||||
return new HalFormsConfiguration().withMediaType(CUSTOM_MEDIA_TYPE);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user