#973 - Explicit configuration options for web stacks.
@EnableHypermediaSupport now exposes a "stacks" attribute to limit the enablement of hypermedia functionality to a certain web stack.
This commit is contained in:
@@ -13,3 +13,18 @@ To let the `RepresentationModel` subtypes be rendered according to the specifica
|
||||
* By default, it enables `@EnableEntityLinks` (see <<fundamentals.obtaining-links.entity-links>>) and automatically picks up `EntityLinks` implementations and bundles them into a `DelegatingEntityLinks` instance that you can autowire.
|
||||
* It automatically picks up all `RelProvider` implementations in the `ApplicationContext` and bundles them into a `DelegatingRelProvider` that you can autowire. It registers providers to consider `@Relation` on domain types as well as Spring MVC controllers. If the https://github.com/atteo/evo-inflector[EVO inflector] is on the classpath, collection `rel` values are derived by using the pluralizing algorithm implemented in the library (see <<spis.rel-provider>>).
|
||||
|
||||
[[configuration.at-enable.stacks]]
|
||||
=== Explicitly enabling support for dedicated web stacks
|
||||
|
||||
By default, `@EnableHypermediaSupport` will reflectively detect the web application stack you're using and hook into the Spring components registered for those to enable support for hypermedia representations.
|
||||
However, there are situations in which you'd only explicitly want to activate support for a particular stack.
|
||||
E.g. if your Spring WebMVC based application uses WebFlux' `WebClient` to make outgoing requests and that one is not supposed to work with hypermedia elements, you can restrict the functionality to be enabled by explicitly declaring WebMvc in the configuration:
|
||||
|
||||
.Explicitly activating hypermedia support for a particular web stack
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@EnableHypermediaSupport(…, stacks = WebStack.WEBMVC)
|
||||
class MyHypermediaConfiguration { … }
|
||||
----
|
||||
====
|
||||
|
||||
@@ -26,7 +26,9 @@ 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
|
||||
@@ -49,6 +51,15 @@ public @interface EnableHypermediaSupport {
|
||||
*/
|
||||
HypermediaType[] type();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
WebStack[] stacks() default { WebStack.WEBMVC, WebStack.WEBFLUX };
|
||||
|
||||
/**
|
||||
* Hypermedia representation types supported.
|
||||
*
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
package org.springframework.hateoas.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.context.annotation.ImportSelector;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
@@ -29,23 +31,44 @@ import org.springframework.hateoas.support.WebStack;
|
||||
*/
|
||||
class WebStackImportSelector implements ImportSelector {
|
||||
|
||||
private static final String WEB_STACK_MISSING = "At least one web stack has to be selected in @EnableHypermediaSupport on %s!";
|
||||
|
||||
static Map<WebStack, String> CONFIGS;
|
||||
|
||||
static {
|
||||
|
||||
Map<WebStack, String> configs = new HashMap<>();
|
||||
|
||||
configs.put(WebStack.WEBMVC, "org.springframework.hateoas.config.WebMvcHateoasConfiguration");
|
||||
configs.put(WebStack.WEBFLUX, "org.springframework.hateoas.config.WebFluxHateoasConfiguration");
|
||||
|
||||
CONFIGS = Collections.unmodifiableMap(configs);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.annotation.ImportSelector#selectImports(org.springframework.core.type.AnnotationMetadata)
|
||||
*/
|
||||
@Override
|
||||
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||
public String[] selectImports(AnnotationMetadata metadata) {
|
||||
|
||||
List<String> imports = new ArrayList<>();
|
||||
Map<String, Object> attributes = metadata.getAnnotationAttributes(EnableHypermediaSupport.class.getName());
|
||||
|
||||
if (WebStack.WEBMVC.isAvailable()) {
|
||||
imports.add("org.springframework.hateoas.config.WebMvcHateoasConfiguration");
|
||||
// Configuration class imported but not through @EnableHypermediaSupport
|
||||
|
||||
if (attributes == null) {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
if (WebStack.WEBFLUX.isAvailable()) {
|
||||
imports.add("org.springframework.hateoas.config.WebFluxHateoasConfiguration");
|
||||
WebStack[] stacks = (WebStack[]) attributes.get("stacks");
|
||||
|
||||
if (stacks.length == 0) {
|
||||
throw new IllegalStateException(String.format(WEB_STACK_MISSING, metadata.getClassName()));
|
||||
}
|
||||
|
||||
return imports.toArray(new String[0]);
|
||||
return Arrays.stream(stacks) //
|
||||
.filter(WebStack::isAvailable) //
|
||||
.map(CONFIGS::get) //
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2019 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
|
||||
*
|
||||
* http://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.config;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
|
||||
import org.springframework.hateoas.support.WebStack;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link WebStackImportSelector}.
|
||||
*
|
||||
* @author Oliver Drotbohm
|
||||
*/
|
||||
public class WebStackImportSelectorUnitTest {
|
||||
|
||||
WebStackImportSelector selector = new WebStackImportSelector();
|
||||
|
||||
@Test // #973
|
||||
public void activatesAllWebStacksByDefault() {
|
||||
|
||||
AnnotationMetadata metadata = new StandardAnnotationMetadata(DefaultHypermedia.class);
|
||||
|
||||
assertThat(selector.selectImports(metadata))
|
||||
.containsExactlyInAnyOrderElementsOf(WebStackImportSelector.CONFIGS.values());
|
||||
}
|
||||
|
||||
@Test // #973
|
||||
public void activatesWebMvcOnlyifConfigured() {
|
||||
|
||||
AnnotationMetadata metadata = new StandardAnnotationMetadata(WebMvcHypermedia.class);
|
||||
|
||||
assertThat(selector.selectImports(metadata)).containsExactly(WebStackImportSelector.CONFIGS.get(WebStack.WEBMVC));
|
||||
}
|
||||
|
||||
@Test // #973
|
||||
public void activatesWebFluxOnlyIfConfigured() {
|
||||
|
||||
AnnotationMetadata metadata = new StandardAnnotationMetadata(WebFluxHypermedia.class);
|
||||
|
||||
assertThat(selector.selectImports(metadata)).containsExactly(WebStackImportSelector.CONFIGS.get(WebStack.WEBFLUX));
|
||||
}
|
||||
|
||||
@Test // #973
|
||||
public void rejectsNoStacksSelected() {
|
||||
|
||||
AnnotationMetadata metadata = new StandardAnnotationMetadata(NoStacksHypermedia.class);
|
||||
|
||||
assertThatExceptionOfType(IllegalStateException.class) //
|
||||
.isThrownBy(() -> selector.selectImports(metadata)) //
|
||||
.withMessageContaining(NoStacksHypermedia.class.getName());
|
||||
}
|
||||
|
||||
@EnableHypermediaSupport(type = HypermediaType.HAL)
|
||||
static class DefaultHypermedia {}
|
||||
|
||||
@EnableHypermediaSupport(type = HypermediaType.HAL, stacks = WebStack.WEBMVC)
|
||||
static class WebMvcHypermedia {}
|
||||
|
||||
@EnableHypermediaSupport(type = HypermediaType.HAL, stacks = WebStack.WEBFLUX)
|
||||
static class WebFluxHypermedia {}
|
||||
|
||||
@EnableHypermediaSupport(type = HypermediaType.HAL, stacks = {})
|
||||
static class NoStacksHypermedia {}
|
||||
}
|
||||
Reference in New Issue
Block a user