diff --git a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java
index 3ad5c3c96..90a3fa034 100755
--- a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java
+++ b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java
@@ -45,6 +45,7 @@ import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.Links;
+import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.server.LinkRelationProvider;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
@@ -731,6 +732,14 @@ public class JpaWebTests extends CommonWebTests {
assertThat(content.read("$.calculatedName", String.class)).isEqualTo("calculated-put");
}
+ @Test // #1991
+ public void answersToHalFormsRequests() throws Exception {
+
+ mvc.perform(get("/")
+ .accept(MediaTypes.HAL_FORMS_JSON))
+ .andExpect(status().isOk());
+ }
+
private List preparePersonResources(Person primary, Person... persons) throws Exception {
Link peopleLink = client.discoverUnique(LinkRelation.of("people"));
diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java
index 616818ea8..c899bb5ce 100644
--- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java
+++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java
@@ -34,6 +34,7 @@ import org.springframework.data.rest.core.mapping.ResourceMetadata;
import org.springframework.data.rest.webmvc.support.JpaHelper;
import org.springframework.data.util.ProxyUtils;
import org.springframework.data.util.Streamable;
+import org.springframework.hateoas.MediaTypes;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;
@@ -217,6 +218,7 @@ public class RepositoryRestHandlerMapping extends BasePathAwareHandlerMapping {
Set mediaTypes = new LinkedHashSet();
mediaTypes.add(configuration.getDefaultMediaType().toString());
mediaTypes.add(MediaType.APPLICATION_JSON_VALUE);
+ mediaTypes.add(MediaTypes.HAL_FORMS_JSON_VALUE);
return new ProducesRequestCondition(mediaTypes.toArray(new String[mediaTypes.size()]));
}
diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java
index 4f423b3a7..68121476a 100644
--- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java
+++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java
@@ -104,6 +104,8 @@ import org.springframework.hateoas.mediatype.hal.DefaultCurieProvider;
import org.springframework.hateoas.mediatype.hal.HalConfiguration;
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule;
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalHandlerInstantiator;
+import org.springframework.hateoas.mediatype.hal.forms.HalFormsConfiguration;
+import org.springframework.hateoas.mediatype.hal.forms.Jackson2HalFormsModule;
import org.springframework.hateoas.server.LinkRelationProvider;
import org.springframework.hateoas.server.core.EvoInflectorLinkRelationProvider;
import org.springframework.hateoas.server.mvc.RepresentationModelProcessorInvoker;
@@ -143,7 +145,7 @@ import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
* @author Christoph Strobl
*/
@Configuration(proxyBeanMethods = false)
-@EnableHypermediaSupport(type = HypermediaType.HAL)
+@EnableHypermediaSupport(type = { HypermediaType.HAL, HypermediaType.HAL_FORMS })
@ImportResource("classpath*:META-INF/spring-data-rest/**/*.xml")
@Import({ RestControllerImportSelector.class, //
SpringDataJacksonConfiguration.class, //
@@ -573,13 +575,45 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
return converter;
}
+ /**
+ * {@link HttpMessageConverter} to support rendering HAL FORMS.
+ *
+ * @param linkCollector
+ * @return
+ * @since 3.5
+ */
+ @Bean
+ TypeConstrainedMappingJackson2HttpMessageConverter halFormsJacksonHttpMessageConverter(LinkCollector linkCollector) {
+
+ LinkRelationProvider defaultedRelProvider = this.relProvider.getIfUnique(EvoInflectorLinkRelationProvider::new);
+ HalFormsConfiguration configuration = new HalFormsConfiguration(
+ halConfiguration.getIfUnique(() -> new HalConfiguration()));
+ CurieProvider curieProvider = this.curieProvider
+ .getIfUnique(() -> new DefaultCurieProvider(Collections.emptyMap()));
+ ObjectMapper mapper = basicObjectMapper();
+
+ mapper.registerModule(persistentEntityJackson2Module(linkCollector));
+ mapper.registerModule(new Jackson2HalFormsModule());
+ mapper.setHandlerInstantiator(new Jackson2HalModule.HalHandlerInstantiator(
+ defaultedRelProvider, curieProvider, resolver.getObject(), configuration.getHalConfiguration(),
+ applicationContext.getAutowireCapableBeanFactory()));
+
+ TypeConstrainedMappingJackson2HttpMessageConverter converter = new TypeConstrainedMappingJackson2HttpMessageConverter(
+ RepresentationModel.class);
+ converter.setSupportedMediaTypes(Collections.singletonList(MediaTypes.HAL_FORMS_JSON));
+ converter.setObjectMapper(mapper);
+
+ return converter;
+ }
+
public ObjectMapper halObjectMapper(LinkCollector linkCollector) {
LinkRelationProvider defaultedRelProvider = this.relProvider.getIfUnique(EvoInflectorLinkRelationProvider::new);
HalConfiguration halConfiguration = this.halConfiguration.getIfUnique(HalConfiguration::new);
- HalHandlerInstantiator instantiator = new HalHandlerInstantiator(defaultedRelProvider,
- curieProvider.getIfUnique(() -> new DefaultCurieProvider(Collections.emptyMap())), resolver.getObject(),
- halConfiguration, applicationContext.getAutowireCapableBeanFactory());
+ CurieProvider curieProvider = this.curieProvider
+ .getIfUnique(() -> new DefaultCurieProvider(Collections.emptyMap()));
+ HalHandlerInstantiator instantiator = new HalHandlerInstantiator(defaultedRelProvider, curieProvider,
+ resolver.getObject(), halConfiguration, applicationContext.getAutowireCapableBeanFactory());
ObjectMapper mapper = basicObjectMapper();
mapper.registerModule(persistentEntityJackson2Module(linkCollector));
@@ -739,6 +773,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
public List> defaultMessageConverters(
@Qualifier("jacksonHttpMessageConverter") TypeConstrainedMappingJackson2HttpMessageConverter jacksonHttpMessageConverter,
@Qualifier("halJacksonHttpMessageConverter") TypeConstrainedMappingJackson2HttpMessageConverter halJacksonHttpMessageConverter,
+ @Qualifier("halFormsJacksonHttpMessageConverter") TypeConstrainedMappingJackson2HttpMessageConverter halFormsJacksonHttpMessageConverter,
AlpsJsonHttpMessageConverter alpsJsonHttpMessageConverter,
UriListHttpMessageConverter uriListHttpMessageConverter, RepositoryRestConfigurerDelegate configurerDelegate,
RepositoryRestConfiguration repositoryRestConfiguration) {
@@ -757,6 +792,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
messageConverters.add(halJacksonHttpMessageConverter);
}
+ messageConverters.add(halFormsJacksonHttpMessageConverter);
+
MappingJackson2HttpMessageConverter fallbackJsonConverter = new MappingJackson2HttpMessageConverter();
fallbackJsonConverter.setObjectMapper(basicObjectMapper());