Skip to content

Commit 30ddf18

Browse files
committed
#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.
1 parent 26a0dd8 commit 30ddf18

File tree

4 files changed

+26
-15
lines changed

4 files changed

+26
-15
lines changed

src/main/asciidoc/server.adoc

+7-7
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,10 @@ curl -v localhost:8080/employees \
267267
[[server.entity-links]]
268268
== [[fundamentals.obtaining-links.entity-links]] Using the EntityLinks interface
269269

270+
IMPORTANT: `EntityLinks` and it's various implementations are NOT currently provided out-of-the-box for Spring WebFlux applications.
271+
The contract defined in the `EntityLinks` SPI was originally aimed at Spring Web MVC and doesn't consider Reactor types.
272+
Developing a comparable contract that supports reactive programming is still in progress.
273+
270274
So far, we have created links by pointing to the web-framework implementations (that is, the Spring MVC controllers) and inspected the mapping.
271275
In many cases, these classes essentially read and write representations backed by a model class.
272276

@@ -285,13 +289,13 @@ Link link = links.linkToItemResource(Customer.class, 1L);
285289

286290
`EntityLinks` is available via dependency injection by activating `@EnableHypermediaSupprt` in your Spring MVC configuration.
287291
This will cause a variety of default implementations of `EntityLinks` being registered.
288-
The most fundamental one is `ControllerEntityLinks` that inspects SpringMVC and Spring WebFlux controller classes.
292+
The most fundamental one is `ControllerEntityLinks` that inspects SpringMVC controller classes.
289293
If you want to register your own implementation of `EntityLinks`, check out <<server.entity-links.spi, this section>>.
290294

291295
[[server.entity-links.controller]]
292-
=== EntityLinks based on Spring MVC and WebFlux controllers
296+
=== EntityLinks based on Spring MVC controllers
293297

294-
Activating entity links functionality causes all the Spring MVC and WebFlux controllers available in the current `ApplicationContext` to be inspected for the `@ExposesResourceFor(…)` annotation.
298+
Activating entity links functionality causes all the Spring MVC controllers available in the current `ApplicationContext` to be inspected for the `@ExposesResourceFor(…)` annotation.
295299
The annotation exposes which model type the controller manages.
296300
Beyond that, we assume that you adhere to following the URI mapping setup and conventions:
297301

@@ -421,10 +425,6 @@ It's registered as primary bean so that it's always the sole injection candidate
421425
`ControllerEntityLinks` is the default implementation that will be included in the setup, but users are free to implement and register their own implementations.
422426
Making those available to the `EntityLinks` instance available for injection is a matter of registering your implementation as Spring bean.
423427

424-
IMPORTANT: `EntityLinks` and it's various implementations are NOT currently provided out-of-the-box for Spring WebFlux applications.
425-
The contract defined in the `EntityLinks` SPI was originally aimed at Spring Web MVC and doesn't consider Reactor types.
426-
Developing a comparable contract that supports reactive programming is still in progress.
427-
428428
.Declaring a custom EntityLinks implementation
429429
====
430430
[source, java]

src/main/java/org/springframework/hateoas/config/HateoasConfiguration.java

-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import org.springframework.context.ApplicationContext;
2929
import org.springframework.context.annotation.Bean;
3030
import org.springframework.context.annotation.Configuration;
31-
import org.springframework.context.annotation.Import;
3231
import org.springframework.context.annotation.Primary;
3332
import org.springframework.context.support.AbstractMessageSource;
3433
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
@@ -58,7 +57,6 @@
5857
* @since 0.19
5958
*/
6059
@Configuration
61-
@Import(EntityLinksConfiguration.class)
6260
@EnablePluginRegistries({ LinkDiscoverer.class })
6361
public class HateoasConfiguration {
6462

src/main/java/org/springframework/hateoas/config/WebMvcEntityLinksConfiguration.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
* @author Oliver Gierke
3131
*/
3232
@Configuration
33-
class WebMvcEntityLinksConfiguration {
33+
class WebMvcEntityLinksConfiguration extends EntityLinksConfiguration {
3434

3535
@Bean
3636
ControllerEntityLinksFactoryBean webMvcEntityLinks(ObjectProvider<WebMvcLinkBuilderFactory> linkBuilderFactory) {

src/test/java/org/springframework/hateoas/config/WebStackImportSelectorUnitTest.java

+18-5
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@
1818
import static org.assertj.core.api.Assertions.*;
1919

2020
import org.junit.jupiter.api.Test;
21+
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
22+
import org.springframework.context.ConfigurableApplicationContext;
23+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
2124
import org.springframework.core.type.AnnotationMetadata;
22-
import org.springframework.core.type.StandardAnnotationMetadata;
2325
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
26+
import org.springframework.hateoas.server.EntityLinks;
2427
import org.springframework.hateoas.support.WebStack;
2528

2629
/**
@@ -35,7 +38,7 @@ class WebStackImportSelectorUnitTest {
3538
@Test // #973
3639
void activatesAllWebStacksByDefault() {
3740

38-
AnnotationMetadata metadata = new StandardAnnotationMetadata(DefaultHypermedia.class);
41+
AnnotationMetadata metadata = AnnotationMetadata.introspect(DefaultHypermedia.class);
3942

4043
assertThat(selector.selectImports(metadata))
4144
.containsExactlyInAnyOrderElementsOf(WebStackImportSelector.CONFIGS.values());
@@ -44,29 +47,39 @@ void activatesAllWebStacksByDefault() {
4447
@Test // #973
4548
void activatesWebMvcOnlyifConfigured() {
4649

47-
AnnotationMetadata metadata = new StandardAnnotationMetadata(WebMvcHypermedia.class);
50+
AnnotationMetadata metadata = AnnotationMetadata.introspect(WebMvcHypermedia.class);
4851

4952
assertThat(selector.selectImports(metadata)).containsExactly(WebStackImportSelector.CONFIGS.get(WebStack.WEBMVC));
5053
}
5154

5255
@Test // #973
5356
void activatesWebFluxOnlyIfConfigured() {
5457

55-
AnnotationMetadata metadata = new StandardAnnotationMetadata(WebFluxHypermedia.class);
58+
AnnotationMetadata metadata = AnnotationMetadata.introspect(WebFluxHypermedia.class);
5659

5760
assertThat(selector.selectImports(metadata)).containsExactly(WebStackImportSelector.CONFIGS.get(WebStack.WEBFLUX));
5861
}
5962

6063
@Test // #973
6164
void rejectsNoStacksSelected() {
6265

63-
AnnotationMetadata metadata = new StandardAnnotationMetadata(NoStacksHypermedia.class);
66+
AnnotationMetadata metadata = AnnotationMetadata.introspect(NoStacksHypermedia.class);
6467

6568
assertThatExceptionOfType(IllegalStateException.class) //
6669
.isThrownBy(() -> selector.selectImports(metadata)) //
6770
.withMessageContaining(NoStacksHypermedia.class.getName());
6871
}
6972

73+
@Test // #1080
74+
void noEntityLinksRegisteredForWebFluxBootstrap() throws Exception {
75+
76+
try (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(WebFluxHypermedia.class)) {
77+
78+
assertThatExceptionOfType(NoSuchBeanDefinitionException.class) //
79+
.isThrownBy(() -> context.getBean(EntityLinks.class));
80+
}
81+
}
82+
7083
@EnableHypermediaSupport(type = HypermediaType.HAL)
7184
static class DefaultHypermedia {}
7285

0 commit comments

Comments
 (0)