#1080 - Improved configuration setup and documentation on EntityLinks.

We now explicitly only enable EntityLinks in WebMVC environments. This is also now reflected properly in the reference documentation.
This commit is contained in:
Oliver Drotbohm
2019-09-26 15:21:35 +02:00
parent 26a0dd8794
commit 30ddf1873c
4 changed files with 26 additions and 15 deletions

View File

@@ -267,6 +267,10 @@ curl -v localhost:8080/employees \
[[server.entity-links]]
== [[fundamentals.obtaining-links.entity-links]] Using the EntityLinks interface
IMPORTANT: `EntityLinks` and it's various implementations are NOT currently provided out-of-the-box for Spring WebFlux applications.
The contract defined in the `EntityLinks` SPI was originally aimed at Spring Web MVC and doesn't consider Reactor types.
Developing a comparable contract that supports reactive programming is still in progress.
So far, we have created links by pointing to the web-framework implementations (that is, the Spring MVC controllers) and inspected the mapping.
In many cases, these classes essentially read and write representations backed by a model class.
@@ -285,13 +289,13 @@ Link link = links.linkToItemResource(Customer.class, 1L);
`EntityLinks` is available via dependency injection by activating `@EnableHypermediaSupprt` in your Spring MVC configuration.
This will cause a variety of default implementations of `EntityLinks` being registered.
The most fundamental one is `ControllerEntityLinks` that inspects SpringMVC and Spring WebFlux controller classes.
The most fundamental one is `ControllerEntityLinks` that inspects SpringMVC controller classes.
If you want to register your own implementation of `EntityLinks`, check out <<server.entity-links.spi, this section>>.
[[server.entity-links.controller]]
=== EntityLinks based on Spring MVC and WebFlux controllers
=== EntityLinks based on Spring MVC controllers
Activating entity links functionality causes all the Spring MVC and WebFlux controllers available in the current `ApplicationContext` to be inspected for the `@ExposesResourceFor(…)` annotation.
Activating entity links functionality causes all the Spring MVC controllers available in the current `ApplicationContext` to be inspected for the `@ExposesResourceFor(…)` annotation.
The annotation exposes which model type the controller manages.
Beyond that, we assume that you adhere to following the URI mapping setup and conventions:
@@ -421,10 +425,6 @@ It's registered as primary bean so that it's always the sole injection candidate
`ControllerEntityLinks` is the default implementation that will be included in the setup, but users are free to implement and register their own implementations.
Making those available to the `EntityLinks` instance available for injection is a matter of registering your implementation as Spring bean.
IMPORTANT: `EntityLinks` and it's various implementations are NOT currently provided out-of-the-box for Spring WebFlux applications.
The contract defined in the `EntityLinks` SPI was originally aimed at Spring Web MVC and doesn't consider Reactor types.
Developing a comparable contract that supports reactive programming is still in progress.
.Declaring a custom EntityLinks implementation
====
[source, java]

View File

@@ -28,7 +28,6 @@ import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.context.support.AbstractMessageSource;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
@@ -58,7 +57,6 @@ import org.springframework.util.ClassUtils;
* @since 0.19
*/
@Configuration
@Import(EntityLinksConfiguration.class)
@EnablePluginRegistries({ LinkDiscoverer.class })
public class HateoasConfiguration {

View File

@@ -30,7 +30,7 @@ import org.springframework.stereotype.Controller;
* @author Oliver Gierke
*/
@Configuration
class WebMvcEntityLinksConfiguration {
class WebMvcEntityLinksConfiguration extends EntityLinksConfiguration {
@Bean
ControllerEntityLinksFactoryBean webMvcEntityLinks(ObjectProvider<WebMvcLinkBuilderFactory> linkBuilderFactory) {

View File

@@ -18,9 +18,12 @@ package org.springframework.hateoas.config;
import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.hateoas.server.EntityLinks;
import org.springframework.hateoas.support.WebStack;
/**
@@ -35,7 +38,7 @@ class WebStackImportSelectorUnitTest {
@Test // #973
void activatesAllWebStacksByDefault() {
AnnotationMetadata metadata = new StandardAnnotationMetadata(DefaultHypermedia.class);
AnnotationMetadata metadata = AnnotationMetadata.introspect(DefaultHypermedia.class);
assertThat(selector.selectImports(metadata))
.containsExactlyInAnyOrderElementsOf(WebStackImportSelector.CONFIGS.values());
@@ -44,7 +47,7 @@ class WebStackImportSelectorUnitTest {
@Test // #973
void activatesWebMvcOnlyifConfigured() {
AnnotationMetadata metadata = new StandardAnnotationMetadata(WebMvcHypermedia.class);
AnnotationMetadata metadata = AnnotationMetadata.introspect(WebMvcHypermedia.class);
assertThat(selector.selectImports(metadata)).containsExactly(WebStackImportSelector.CONFIGS.get(WebStack.WEBMVC));
}
@@ -52,7 +55,7 @@ class WebStackImportSelectorUnitTest {
@Test // #973
void activatesWebFluxOnlyIfConfigured() {
AnnotationMetadata metadata = new StandardAnnotationMetadata(WebFluxHypermedia.class);
AnnotationMetadata metadata = AnnotationMetadata.introspect(WebFluxHypermedia.class);
assertThat(selector.selectImports(metadata)).containsExactly(WebStackImportSelector.CONFIGS.get(WebStack.WEBFLUX));
}
@@ -60,13 +63,23 @@ class WebStackImportSelectorUnitTest {
@Test // #973
void rejectsNoStacksSelected() {
AnnotationMetadata metadata = new StandardAnnotationMetadata(NoStacksHypermedia.class);
AnnotationMetadata metadata = AnnotationMetadata.introspect(NoStacksHypermedia.class);
assertThatExceptionOfType(IllegalStateException.class) //
.isThrownBy(() -> selector.selectImports(metadata)) //
.withMessageContaining(NoStacksHypermedia.class.getName());
}
@Test // #1080
void noEntityLinksRegisteredForWebFluxBootstrap() throws Exception {
try (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(WebFluxHypermedia.class)) {
assertThatExceptionOfType(NoSuchBeanDefinitionException.class) //
.isThrownBy(() -> context.getBean(EntityLinks.class));
}
}
@EnableHypermediaSupport(type = HypermediaType.HAL)
static class DefaultHypermedia {}