diff --git a/src/main/java/org/springframework/hateoas/IanaRels.java b/src/main/java/org/springframework/hateoas/IanaRels.java deleted file mode 100644 index 19b11f1e..00000000 --- a/src/main/java/org/springframework/hateoas/IanaRels.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013-2020 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; - -/** - * Static class to find out whether a relation type is defined by the IANA. - * - * @see https://www.iana.org/assignments/link-relations/link-relations.xhtml - * @author Oliver Gierke - * @author Roland Kulcsár - * @author Greg Turnquist - */ -@Deprecated -public final class IanaRels { - - private IanaRels() { - throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); - } - - /** - * Returns whether the given relation type is defined by the IANA. - * - * @param rel the relation type to check - * @return - * @deprecated Migrate to {@link IanaLinkRelations#isIanaRel(String)}. - */ - @Deprecated - public static boolean isIanaRel(String rel) { - return IanaLinkRelations.isIanaRel(rel); - } -} diff --git a/src/main/java/org/springframework/hateoas/server/mvc/ControllerLinkBuilder.java b/src/main/java/org/springframework/hateoas/server/mvc/ControllerLinkBuilder.java deleted file mode 100755 index 27e3a840..00000000 --- a/src/main/java/org/springframework/hateoas/server/mvc/ControllerLinkBuilder.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright 2012-2020 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.server.mvc; - -import java.lang.reflect.Method; -import java.net.URI; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.springframework.hateoas.Affordance; -import org.springframework.hateoas.Link; -import org.springframework.hateoas.TemplateVariables; -import org.springframework.hateoas.server.core.AnnotationMappingDiscoverer; -import org.springframework.hateoas.server.core.CachingMappingDiscoverer; -import org.springframework.hateoas.server.core.DummyInvocationUtils; -import org.springframework.hateoas.server.core.MappingDiscoverer; -import org.springframework.hateoas.server.core.TemplateVariableAwareLinkBuilderSupport; -import org.springframework.hateoas.server.core.UriTemplateFactory; -import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.util.DefaultUriTemplateHandler; -import org.springframework.web.util.UriComponents; -import org.springframework.web.util.UriComponentsBuilder; -import org.springframework.web.util.UriTemplate; - -/** - * Builder to ease building {@link Link} instances pointing to Spring MVC controllers. - * - * @author Oliver Gierke - * @author Kamill Sokol - * @author Greg Turnquist - * @author Kevin Conaway - * @author Andrew Naydyonock - * @author Oliver Trosien - * @author Greg Turnquist - * @deprecated use {@link WebMvcLinkBuilder} instead. - */ -@Deprecated -public class ControllerLinkBuilder extends TemplateVariableAwareLinkBuilderSupport { - - private static final MappingDiscoverer DISCOVERER = CachingMappingDiscoverer - .of(new AnnotationMappingDiscoverer(RequestMapping.class)); - private static final ControllerLinkBuilderFactory FACTORY = new ControllerLinkBuilderFactory(); - private static final CustomUriTemplateHandler HANDLER = new CustomUriTemplateHandler(); - - /** - * Creates a new {@link ControllerLinkBuilder} using the given {@link UriComponentsBuilder}. - * - * @param builder must not be {@literal null}. - */ - ControllerLinkBuilder(UriComponents components) { - this(components, TemplateVariables.NONE, Collections.emptyList()); - } - - ControllerLinkBuilder(UriComponents components, TemplateVariables variables, List affordances) { - super(components, variables, affordances); - } - - /** - * Creates a new {@link ControllerLinkBuilder} with a base of the mapping annotated to the given controller class. - * - * @param controller the class to discover the annotation on, must not be {@literal null}. - * @return - */ - public static ControllerLinkBuilder linkTo(Class controller) { - return linkTo(controller, new Object[0]); - } - - /** - * Creates a new {@link ControllerLinkBuilder} with a base of the mapping annotated to the given controller class. The - * additional parameters are used to fill up potentially available path variables in the class scop request mapping. - * - * @param controller the class to discover the annotation on, must not be {@literal null}. - * @param parameters additional parameters to bind to the URI template declared in the annotation, must not be - * {@literal null}. - * @return - */ - public static ControllerLinkBuilder linkTo(Class controller, Object... parameters) { - - Assert.notNull(controller, "Controller must not be null!"); - Assert.notNull(parameters, "Parameters must not be null!"); - - String mapping = DISCOVERER.getMapping(controller); - - UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(mapping == null ? "/" : mapping); - UriComponents uriComponents = HANDLER.expandAndEncode(builder, parameters); - - return new ControllerLinkBuilder(UriComponentsBuilderFactory.getComponents()).slash(uriComponents, true); - } - - /** - * Creates a new {@link ControllerLinkBuilder} with a base of the mapping annotated to the given controller class. - * Parameter map is used to fill up potentially available path variables in the class scope request mapping. - * - * @param controller the class to discover the annotation on, must not be {@literal null}. - * @param parameters additional parameters to bind to the URI template declared in the annotation, must not be - * {@literal null}. - * @return - */ - public static ControllerLinkBuilder linkTo(Class controller, Map parameters) { - - Assert.notNull(controller, "Controller must not be null!"); - Assert.notNull(parameters, "Parameters must not be null!"); - - String mapping = DISCOVERER.getMapping(controller); - - UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(mapping == null ? "/" : mapping); - UriComponents uriComponents = HANDLER.expandAndEncode(builder, parameters); - - return new ControllerLinkBuilder(UriComponentsBuilderFactory.getComponents()).slash(uriComponents, true); - } - - /* - * @see org.springframework.hateoas.MethodLinkBuilderFactory#linkTo(Method, Object...) - */ - public static ControllerLinkBuilder linkTo(Method method, Object... parameters) { - return linkTo(method.getDeclaringClass(), method, parameters); - } - - /* - * @see org.springframework.hateoas.MethodLinkBuilderFactory#linkTo(Class, Method, Object...) - */ - public static ControllerLinkBuilder linkTo(Class controller, Method method, Object... parameters) { - - Assert.notNull(controller, "Controller type must not be null!"); - Assert.notNull(method, "Method must not be null!"); - - UriTemplate template = UriTemplateFactory.templateFor(DISCOVERER.getMapping(controller, method)); - URI uri = template.expand(parameters); - - return new ControllerLinkBuilder(UriComponentsBuilderFactory.getComponents()).slash(uri); - } - - /** - * Creates a {@link ControllerLinkBuilder} pointing to a controller method. Hand in a dummy method invocation result - * you can create via {@link #methodOn(Class, Object...)} or {@link DummyInvocationUtils#methodOn(Class, Object...)}. - * - *
-	 * @RequestMapping("/customers")
-	 * class CustomerController {
-	 *
-	 *   @RequestMapping("/{id}/addresses")
-	 *   HttpEntity<Addresses> showAddresses(@PathVariable Long id) { … }
-	 * }
-	 *
-	 * Link link = linkTo(methodOn(CustomerController.class).showAddresses(2L)).withRel("addresses");
-	 * 
- * - * The resulting {@link Link} instance will point to {@code /customers/2/addresses} and have a rel of - * {@code addresses}. For more details on the method invocation constraints, see - * {@link DummyInvocationUtils#methodOn(Class, Object...)}. - * - * @param invocationValue - * @return - */ - public static ControllerLinkBuilder linkTo(Object invocationValue) { - return FACTORY.linkTo(invocationValue); - } - - /** - * Extract a {@link Link} from the {@link ControllerLinkBuilder} and look up the related {@link Affordance}. Should - * only be one. - * - *
-	 * Link findOneLink = linkTo(methodOn(EmployeeController.class).findOne(id)).withSelfRel()
-	 * 		.andAffordance(afford(methodOn(EmployeeController.class).updateEmployee(null, id)));
-	 * 
- * - * This takes a link and adds an {@link Affordance} based on another Spring MVC handler method. - * - * @param invocationValue - * @return - */ - public static Affordance afford(Object invocationValue) { - - ControllerLinkBuilder linkBuilder = linkTo(invocationValue); - - Assert.isTrue(linkBuilder.getAffordances().size() == 1, "A base can only have one affordance, itself"); - - return linkBuilder.getAffordances().get(0); - } - - /** - * Wrapper for {@link DummyInvocationUtils#methodOn(Class, Object...)} to be available in case you work with static - * imports of {@link ControllerLinkBuilder}. - * - * @param controller must not be {@literal null}. - * @param parameters parameters to extend template variables in the type level mapping. - * @return - */ - public static T methodOn(Class controller, Object... parameters) { - return DummyInvocationUtils.methodOn(controller, parameters); - } - - /* - * (non-Javadoc) - * @see org.springframework.hateoas.UriComponentsLinkBuilder#getThis() - */ - @Override - protected ControllerLinkBuilder getThis() { - return this; - } - - /* - * (non-Javadoc) - * @see org.springframework.hateoas.core.TemplateVariableAwareLinkBuilderSupport#createNewInstance(org.springframework.web.util.UriComponentsBuilder, java.util.List, org.springframework.hateoas.TemplateVariables) - */ - @Override - protected ControllerLinkBuilder createNewInstance(UriComponents components, List affordances, - TemplateVariables variables) { - return new ControllerLinkBuilder(components, variables, affordances); - } - - /** - * Returns a {@link UriComponentsBuilder} to continue to build the already built URI in a more fine grained way. - * - * @return - */ - public UriComponentsBuilder toUriComponentsBuilder() { - return UriComponentsBuilder.fromUri(toUri()); - } - - /** - * Returns a {@link UriComponentsBuilder} obtained from the current servlet mapping. If no - * {@link RequestContextHolder} exists (you're outside a Spring Web call), fall back to relative URIs. - * - * @return - */ - public static UriComponentsBuilder getBuilder() { - return UriComponentsBuilderFactory.getBuilder(); - } - - private static class CustomUriTemplateHandler extends DefaultUriTemplateHandler { - - public CustomUriTemplateHandler() { - setStrictEncoding(true); - } - - /* - * (non-Javadoc) - * @see org.springframework.web.util.DefaultUriTemplateHandler#expandAndEncode(org.springframework.web.util.UriComponentsBuilder, java.util.Map) - */ - @Override - public UriComponents expandAndEncode(UriComponentsBuilder builder, Map uriVariables) { - return super.expandAndEncode(builder, uriVariables); - } - - /* - * (non-Javadoc) - * @see org.springframework.web.util.DefaultUriTemplateHandler#expandAndEncode(org.springframework.web.util.UriComponentsBuilder, java.lang.Object[]) - */ - @Override - public UriComponents expandAndEncode(UriComponentsBuilder builder, Object[] uriVariables) { - return super.expandAndEncode(builder, uriVariables); - } - } -} diff --git a/src/main/java/org/springframework/hateoas/server/mvc/ControllerLinkBuilderFactory.java b/src/main/java/org/springframework/hateoas/server/mvc/ControllerLinkBuilderFactory.java deleted file mode 100644 index b54e5e63..00000000 --- a/src/main/java/org/springframework/hateoas/server/mvc/ControllerLinkBuilderFactory.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2012-2020 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.server.mvc; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.springframework.core.MethodParameter; -import org.springframework.hateoas.Link; -import org.springframework.hateoas.server.MethodLinkBuilderFactory; -import org.springframework.hateoas.server.core.LinkBuilderSupport; -import org.springframework.hateoas.server.core.MethodParameters; -import org.springframework.hateoas.server.core.WebHandler; - -/** - * Factory for {@link LinkBuilderSupport} instances based on the request mapping annotated on the given controller. - * - * @author Ricardo Gladwell - * @author Oliver Gierke - * @author Dietrich Schulten - * @author Kamill Sokol - * @author Ross Turner - * @author Oemer Yildiz - * @author Kevin Conaway - * @author Andrew Naydyonock - * @author Greg Turnquist - * @deprecated use {@link WebMvcLinkBuilderFactory} instead. - */ -@Deprecated -public class ControllerLinkBuilderFactory implements MethodLinkBuilderFactory { - - private List uriComponentsContributors = new ArrayList<>(); - - /** - * Configures the {@link UriComponentsContributor} to be used when building {@link Link} instances from method - * invocations. - * - * @see #linkTo(Object) - * @param uriComponentsContributors the uriComponentsContributors to set - */ - public void setUriComponentsContributors(List uriComponentsContributors) { - this.uriComponentsContributors = Collections.unmodifiableList(uriComponentsContributors); - } - - /* - * (non-Javadoc) - * @see org.springframework.hateoas.LinkBuilderFactory#linkTo(java.lang.Class) - */ - @Override - public ControllerLinkBuilder linkTo(Class controller) { - return ControllerLinkBuilder.linkTo(controller); - } - - /* - * (non-Javadoc) - * @see org.springframework.hateoas.LinkBuilderFactory#linkTo(java.lang.Class, java.lang.Object[]) - */ - @Override - public ControllerLinkBuilder linkTo(Class controller, Object... parameters) { - return ControllerLinkBuilder.linkTo(controller, parameters); - } - - /* - * (non-Javadoc) - * @see org.springframework.hateoas.LinkBuilderFactory#linkTo(java.lang.Class, java.util.Map) - */ - @Override - public ControllerLinkBuilder linkTo(Class controller, Map parameters) { - return ControllerLinkBuilder.linkTo(controller, parameters); - } - - /* - * (non-Javadoc) - * @see org.springframework.hateoas.MethodLinkBuilderFactory#linkTo(java.lang.Class, java.lang.reflect.Method, java.lang.Object[]) - */ - @Override - public ControllerLinkBuilder linkTo(Class controller, Method method, Object... parameters) { - return ControllerLinkBuilder.linkTo(controller, method, parameters); - } - - /* - * (non-Javadoc) - * @see org.springframework.hateoas.MethodLinkBuilderFactory#linkTo(java.lang.Object) - */ - @Override - public ControllerLinkBuilder linkTo(Object invocationValue) { - - return WebHandler.linkTo(invocationValue, ControllerLinkBuilder::new, (builder, invocation) -> { - - MethodParameters parameters = MethodParameters.of(invocation.getMethod()); - Iterator parameterValues = Arrays.asList(invocation.getArguments()).iterator(); - - for (MethodParameter parameter : parameters.getParameters()) { - Object parameterValue = parameterValues.next(); - - for (UriComponentsContributor contributor : this.uriComponentsContributors) { - - if (contributor.supportsParameter(parameter)) { - contributor.enhance(builder, parameter, parameterValue); - } - } - } - - return builder; - }, mapping -> ControllerLinkBuilder.getBuilder().path(mapping)); - } - - /* - * (non-Javadoc) - * @see org.springframework.hateoas.MethodLinkBuilderFactory#linkTo(java.lang.reflect.Method, java.lang.Object[]) - */ - @Override - public ControllerLinkBuilder linkTo(Method method, Object... parameters) { - return ControllerLinkBuilder.linkTo(method, parameters); - } -} diff --git a/src/test/java/org/springframework/hateoas/server/mvc/ControllerLinkBuilderFactoryUnitTest.java b/src/test/java/org/springframework/hateoas/server/mvc/ControllerLinkBuilderFactoryUnitTest.java deleted file mode 100755 index 922bda8f..00000000 --- a/src/test/java/org/springframework/hateoas/server/mvc/ControllerLinkBuilderFactoryUnitTest.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2012-2020 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.server.mvc; - -import static org.assertj.core.api.Assertions.*; -import static org.springframework.hateoas.server.mvc.ControllerLinkBuilder.*; - -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.joda.time.DateTime; -import org.joda.time.format.ISODateTimeFormat; -import org.junit.jupiter.api.Test; -import org.springframework.core.MethodParameter; -import org.springframework.format.annotation.DateTimeFormat; -import org.springframework.format.annotation.DateTimeFormat.ISO; -import org.springframework.hateoas.IanaLinkRelations; -import org.springframework.hateoas.Link; -import org.springframework.hateoas.TestUtils; -import org.springframework.hateoas.server.mvc.ControllerLinkBuilderUnitTest.ControllerWithMethods; -import org.springframework.hateoas.server.mvc.ControllerLinkBuilderUnitTest.PersonControllerImpl; -import org.springframework.hateoas.server.mvc.ControllerLinkBuilderUnitTest.PersonsAddressesController; -import org.springframework.http.HttpEntity; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.util.UriComponentsBuilder; - -/** - * Unit tests for {@link ControllerLinkBuilderFactory}. - * - * @author Ricardo Gladwell - * @author Oliver Gierke - * @author Kamill Sokol - * @author Ross Turner - */ -@Deprecated -class ControllerLinkBuilderFactoryUnitTest extends TestUtils { - - ControllerLinkBuilderFactory factory = new ControllerLinkBuilderFactory(); - - @Test - void createsLinkToControllerRoot() { - - Link link = factory.linkTo(PersonControllerImpl.class).withSelfRel(); - - assertPointsToMockServer(link); - assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF); - assertThat(link.getHref()).endsWith("/people"); - } - - @Test - void createsLinkToParameterizedControllerRoot() { - - Link link = factory.linkTo(PersonsAddressesController.class, 15).withSelfRel(); - - assertPointsToMockServer(link); - assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF); - assertThat(link.getHref()).endsWith("/people/15/addresses"); - } - - @Test - void appliesParameterValueIfContributorConfigured() { - - ControllerLinkBuilderFactory factory = new ControllerLinkBuilderFactory(); - factory.setUriComponentsContributors(Collections.singletonList(new SampleUriComponentsContributor())); - - SpecialType specialType = new SpecialType(); - specialType.parameterValue = "value"; - - Link link = factory.linkTo(methodOn(SampleController.class).sampleMethod(1L, specialType)).withSelfRel(); - assertPointsToMockServer(link); - assertThat(link.getHref()).endsWith("/sample/1?foo=value"); - } - - /** - * @see #57 - */ - @Test - void usesDateTimeFormatForUriBinding() { - - DateTime now = DateTime.now(); - - ControllerLinkBuilderFactory factory = new ControllerLinkBuilderFactory(); - Link link = factory.linkTo(methodOn(SampleController.class).sampleMethod(now)).withSelfRel(); - assertThat(link.getHref()).endsWith("/sample/" + ISODateTimeFormat.date().print(now)); - } - - /** - * @see #96 - */ - @Test - void linksToMethodWithPathVariableContainingBlank() { - - Link link = linkTo(methodOn(ControllerWithMethods.class).methodWithPathVariable("with blank")).withSelfRel(); - assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF); - assertThat(link.getHref()).endsWith("/something/with%20blank/foo"); - } - - /** - * @see #96 - */ - @Test - void createsLinkToParameterizedControllerRootContainingBlank() { - - Link link = factory.linkTo(PersonsAddressesController.class, "with blank").withSelfRel(); - - assertPointsToMockServer(link); - assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF); - assertThat(link.getHref()).endsWith("/people/with%20blank/addresses"); - } - - /** - * @see #209 - */ - @Test - void createsLinkToControllerMethodWithMapRequestParam() { - - Map queryParams = new LinkedHashMap<>(); - queryParams.put("firstKey", "firstValue"); - queryParams.put("secondKey", "secondValue"); - - Link link = factory.linkTo(methodOn(SampleController.class).sampleMethodWithMap(queryParams)).withSelfRel(); - - assertPointsToMockServer(link); - assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF); - assertThat(link.getHref()).endsWith("/sample/mapsupport?firstKey=firstValue&secondKey=secondValue"); - } - - /** - * @see #209 - */ - @Test - void createsLinkToControllerMethodWithMultiValueMapRequestParam() { - - MultiValueMap queryParams = new LinkedMultiValueMap<>(); - queryParams.put("key1", Arrays.asList("value1a", "value1b")); - queryParams.put("key2", Arrays.asList("value2a", "value2b")); - - Link link = factory.linkTo(methodOn(SampleController.class).sampleMethodWithMap(queryParams)).withSelfRel(); - - assertPointsToMockServer(link); - assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF); - assertThat(link.getHref()) // - .endsWith("/sample/multivaluemapsupport?key1=value1a&key1=value1b&key2=value2a&key2=value2b"); - } - - /** - * @see #372 - */ - @Test - void createsLinkToParameterizedControllerRootWithParameterMap() { - - Link link = factory.linkTo(PersonsAddressesController.class, Collections.singletonMap("id", "17")).withSelfRel(); - - assertPointsToMockServer(link); - assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF); - assertThat(link.getHref()).endsWith("/people/17/addresses"); - } - - interface SampleController { - - @RequestMapping("/sample/{id}") - HttpEntity sampleMethod(@PathVariable("id") Long id, SpecialType parameter); - - @RequestMapping("/sample/{time}") - HttpEntity sampleMethod(@PathVariable("time") @DateTimeFormat(iso = ISO.DATE) DateTime time); - - @RequestMapping("/sample/mapsupport") - HttpEntity sampleMethodWithMap(@RequestParam Map queryParams); - - @RequestMapping("/sample/multivaluemapsupport") - HttpEntity sampleMethodWithMap(@RequestParam MultiValueMap queryParams); - } - - static class SampleUriComponentsContributor implements UriComponentsContributor { - - @Override - public boolean supportsParameter(MethodParameter parameter) { - return SpecialType.class.equals(parameter.getParameterType()); - } - - @Override - public void enhance(UriComponentsBuilder builder, MethodParameter parameter, Object value) { - builder.queryParam("foo", ((SpecialType) value).parameterValue); - } - } - - static class SpecialType { - String parameterValue; - } -} diff --git a/src/test/java/org/springframework/hateoas/server/mvc/ControllerLinkBuilderOutsideSpringMvcUnitTest.java b/src/test/java/org/springframework/hateoas/server/mvc/ControllerLinkBuilderOutsideSpringMvcUnitTest.java deleted file mode 100755 index aabf6e2d..00000000 --- a/src/test/java/org/springframework/hateoas/server/mvc/ControllerLinkBuilderOutsideSpringMvcUnitTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2017-2020 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.server.mvc; - -import static org.assertj.core.api.Assertions.*; -import static org.springframework.hateoas.server.mvc.ControllerLinkBuilder.*; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.hateoas.Link; -import org.springframework.web.context.request.RequestContextHolder; - -/** - * Test cases for {@link ControllerLinkBuilder} that are NOT inside an existing Spring MVC request - * - * @author Greg Turnquist - */ -@Deprecated -class ControllerLinkBuilderOutsideSpringMvcUnitTest { - - /** - * Clear out any existing request attributes left behind by other tests - */ - @BeforeEach - void setUp() { - RequestContextHolder.setRequestAttributes(null); - } - - /** - * @see #408 - */ - @Test - void requestingLinkOutsideWebRequest() { - - Link link = linkTo( - methodOn(ControllerLinkBuilderUnitTest.PersonsAddressesController.class, 15).getAddressesForCountry("DE")) - .withSelfRel(); - - assertThat(link).isEqualTo(Link.of("/people/15/addresses/DE").withSelfRel()); - } -} diff --git a/src/test/java/org/springframework/hateoas/server/mvc/ControllerLinkBuilderUnitTest.java b/src/test/java/org/springframework/hateoas/server/mvc/ControllerLinkBuilderUnitTest.java deleted file mode 100755 index 621dd75b..00000000 --- a/src/test/java/org/springframework/hateoas/server/mvc/ControllerLinkBuilderUnitTest.java +++ /dev/null @@ -1,716 +0,0 @@ -/* - * Copyright 2012-2020 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.server.mvc; - -import static org.assertj.core.api.Assertions.*; -import static org.springframework.hateoas.server.mvc.ControllerLinkBuilder.*; - -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; - -import org.junit.jupiter.api.Test; -import org.springframework.hateoas.IanaLinkRelations; -import org.springframework.hateoas.Link; -import org.springframework.hateoas.TemplateVariable; -import org.springframework.hateoas.TemplateVariable.VariableType; -import org.springframework.hateoas.TestUtils; -import org.springframework.http.HttpEntity; -import org.springframework.util.MultiValueMap; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.util.UriComponents; -import org.springframework.web.util.UriComponentsBuilder; - -/** - * Unit tests for {@link ControllerLinkBuilder}. - * - * @author Oliver Gierke - * @author Dietrich Schulten - * @author Kamill Sokol - * @author Oemer Yildiz - * @author Greg Turnquist - * @author Kevin Conaway - * @author Oliver Trosien - * @author Greg Turnquist - */ -@Deprecated -class ControllerLinkBuilderUnitTest extends TestUtils { - - @Test - void createsLinkToControllerRoot() { - - Link link = linkTo(PersonControllerImpl.class).withSelfRel(); - assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF); - assertThat(link.getHref()).endsWith("/people"); - } - - @Test - void createsLinkToParameterizedControllerRoot() { - - Link link = linkTo(PersonsAddressesController.class, 15).withSelfRel(); - - assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF); - assertThat(link.getHref()).endsWith("/people/15/addresses"); - } - - /** - * @see #70 - */ - @Test - void createsLinkToMethodOnParameterizedControllerRoot() { - - Link link = linkTo(methodOn(PersonsAddressesController.class, 15).getAddressesForCountry("DE")).withSelfRel(); - assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF); - assertThat(link.getHref()).endsWith("/people/15/addresses/DE"); - } - - @Test - void createsLinkToSubResource() { - - Link link = linkTo(PersonControllerImpl.class).slash("something").withSelfRel(); - assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF); - assertThat(link.getHref()).endsWith("/people/something"); - } - - @Test - void createsLinkWithCustomRel() { - - Link link = linkTo(PersonControllerImpl.class).withRel(IanaLinkRelations.NEXT); - - assertThat(link.getRel()).isEqualTo(IanaLinkRelations.NEXT); - assertThat(link.getHref()).endsWith("/people"); - } - - /** - * @see #186 - */ - @Test - void usesFirstMappingInCaseMultipleOnesAreDefined() { - assertThat(linkTo(InvalidController.class).withSelfRel().getHref()).endsWith("/persons"); - } - - @Test - void createsLinkToUnmappedController() { - - Link link = linkTo(UnmappedController.class).withSelfRel(); - assertThat(link.getHref()).isEqualTo("http://localhost"); - } - - @Test - void appendingNullIsANoOp() { - - Link link = linkTo(PersonControllerImpl.class).slash(null).withSelfRel(); - assertThat(link.getHref()).endsWith("/people"); - - link = linkTo(PersonControllerImpl.class).slash((Object) null).withSelfRel(); - assertThat(link.getHref()).endsWith("/people"); - } - - @Test - void linksToMethod() { - - Link link = linkTo(methodOn(ControllerWithMethods.class).myMethod(null)).withSelfRel(); - assertPointsToMockServer(link); - assertThat(link.getHref()).endsWith("/something/else"); - } - - @Test - void linksToMethodWithPathVariable() { - - Link link = linkTo(methodOn(ControllerWithMethods.class).methodWithPathVariable("1")).withSelfRel(); - assertPointsToMockServer(link); - assertThat(link.getHref()).endsWith("/something/1/foo"); - } - - /** - * @see #33 - */ - @Test - void usesForwardedHostAsHostIfHeaderIsSet() { - - request.addHeader("X-Forwarded-Host", "somethingDifferent"); - - adaptRequestFromForwardedHeaders(); - - Link link = linkTo(PersonControllerImpl.class).withSelfRel(); - assertThat(link.getHref()).startsWith("http://somethingDifferent"); - } - - /** - * @see #112 - */ - @Test - void usesForwardedSslIfHeaderIsSet() { - - request.addHeader("X-Forwarded-Ssl", "on"); - - adaptRequestFromForwardedHeaders(); - - Link link = linkTo(PersonControllerImpl.class).withSelfRel(); - assertThat(link.getHref()).startsWith("https://"); - } - - /** - * @see #112 - */ - @Test - void usesForwardedSslIfHeaderIsSetOff() { - - request.addHeader("X-Forwarded-Ssl", "off"); - - adaptRequestFromForwardedHeaders(); - - Link link = linkTo(PersonControllerImpl.class).withSelfRel(); - assertThat(link.getHref()).startsWith("http://"); - } - - /** - * @see #112 - */ - @Test - void usesForwardedSslAndHostIfHeaderIsSet() { - - request.addHeader("X-Forwarded-Host", "somethingDifferent"); - request.addHeader("X-Forwarded-Ssl", "on"); - - adaptRequestFromForwardedHeaders(); - - Link link = linkTo(PersonControllerImpl.class).withSelfRel(); - assertThat(link.getHref()).startsWith("https://somethingDifferent"); - } - - /** - * @see #26, #39 - */ - @Test - void addsRequestParametersHandedIntoSlashCorrectly() { - - Link link = linkTo(PersonController.class).slash("?foo=bar").withSelfRel(); - - UriComponents components = toComponents(link); - assertThat(components.getQuery()).isEqualTo("foo=bar"); - } - - /** - * @see #26, #39 - */ - @Test - void linksToMethodWithPathVariableAndRequestParams() { - - Link link = linkTo(methodOn(ControllerWithMethods.class).methodForNextPage("1", 10, 5)).withSelfRel(); - - UriComponents components = toComponents(link); - assertThat(components.getPath()).isEqualTo("/something/1/foo"); - - MultiValueMap queryParams = components.getQueryParams(); - assertThat(queryParams.get("limit")).containsExactly("5"); - assertThat(queryParams.get("offset")).containsExactly("10"); - } - - /** - * @see #26, #39 - */ - @Test - void linksToMethodWithPathVariableAndMultiValueRequestParams() { - - Link link = linkTo( - methodOn(ControllerWithMethods.class).methodWithMultiValueRequestParams("1", Arrays.asList(3, 7), 5)) - .withSelfRel(); - - UriComponents components = toComponents(link); - assertThat(components.getPath()).isEqualTo("/something/1/foo"); - - MultiValueMap queryParams = components.getQueryParams(); - assertThat(queryParams.get("limit")).containsExactly("5"); - assertThat(queryParams.get("items")).containsExactlyInAnyOrder("3", "7"); - } - - /** - * @see #26, #39 - */ - @Test - void returnsUriComponentsBuilder() { - - UriComponents components = linkTo(PersonController.class).slash("something?foo=bar").toUriComponentsBuilder() - .build(); - - assertThat(components.getPath()).isEqualTo("/people/something"); - assertThat(components.getQuery()).isEqualTo("foo=bar"); - } - - /** - * @see #90 - */ - @Test - void usesForwardedHostAndPortFromHeader() { - - request.addHeader("X-Forwarded-Host", "foobar:8088"); - - adaptRequestFromForwardedHeaders(); - - Link link = linkTo(PersonControllerImpl.class).withSelfRel(); - assertThat(link.getHref()).startsWith("http://foobar:8088"); - } - - /** - * @see #90 - */ - @Test - void usesFirstHostOfXForwardedHost() { - - request.addHeader("X-Forwarded-Host", "barfoo:8888, localhost:8088"); - - adaptRequestFromForwardedHeaders(); - - Link link = linkTo(PersonControllerImpl.class).withSelfRel(); - assertThat(link.getHref()).startsWith("http://barfoo:8888"); - } - - /** - * @see #122, #169 - */ - @Test - void appendsOptionalParameterVariableForUnsetParameter() { - - Link link = linkTo(methodOn(ControllerWithMethods.class).methodForOptionalNextPage(null)).withSelfRel(); - - assertThat(link.getVariables()).containsExactly(new TemplateVariable("offset", VariableType.REQUEST_PARAM)); - assertThat(link.expand().getHref()).endsWith("/foo"); - } - - /** - * @see #122, #169 - */ - @Test - void rejectsMissingPathVariable() { - - ControllerLinkBuilder builder = linkTo(methodOn(ControllerWithMethods.class).methodWithPathVariable(null)); - - assertThatIllegalArgumentException().isThrownBy(() -> { - builder.withSelfRel().expand(); - }); - } - - /** - * @see #122, #169 - */ - @Test - void rejectsMissingRequiredRequestParam() { - - Link link = linkTo(methodOn(ControllerWithMethods.class).methodWithRequestParam(null)).withSelfRel(); - - assertThat(link.getVariableNames()).containsExactly("id"); - assertThatIllegalArgumentException().isThrownBy(() -> { - - link.expand(); - }); - } - - /** - * @see #170 - */ - @Test - void usesForwardedPortFromHeader() { - - request.addHeader("X-Forwarded-Host", "foobarhost"); - request.addHeader("X-Forwarded-Port", "9090"); - request.setServerPort(8080); - - adaptRequestFromForwardedHeaders(); - - Link link = linkTo(PersonControllerImpl.class).withSelfRel(); - - assertThat(link.getHref()).startsWith("http://foobarhost:9090/"); - } - - /** - * @see #170 - */ - @Test - void usesForwardedHostFromHeaderWithDefaultPort() { - - request.addHeader("X-Forwarded-Host", "foobarhost"); - request.setServerPort(8080); - - adaptRequestFromForwardedHeaders(); - - Link link = linkTo(PersonControllerImpl.class).withSelfRel(); - assertThat(link.getHref()).startsWith("http://foobarhost/"); - } - - /** - * @see #114 - */ - @Test - void discoversParentClassTypeMappingForInvocation() { - - Link link = linkTo(methodOn(ChildController.class).myMethod()).withSelfRel(); - assertThat(link.getHref()).endsWith("/parent/child"); - } - - /** - * @see #114 - */ - @Test - void includesTypeMappingFromChildClass() { - - Link link = linkTo(methodOn(ChildWithTypeMapping.class).myMethod()).withSelfRel(); - assertThat(link.getHref()).endsWith("/child/parent"); - } - - /** - * @see #96 - */ - @Test - void linksToMethodWithPathVariableContainingBlank() { - - Link link = linkTo(methodOn(ControllerWithMethods.class).methodWithPathVariable("with blank")).withSelfRel(); - - assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF); - assertThat(link.getHref()).endsWith("/something/with%20blank/foo"); - } - - /** - * @see #192 - */ - @Test - void usesRootMappingOfTargetClassForMethodsOfParentClass() { - - Link link = linkTo(methodOn(ChildControllerWithRootMapping.class) // - .someEmptyMappedMethod()) // - .withSelfRel(); - - assertThat(link.getHref()).endsWith("/root"); - } - - /** - * @see #192 - */ - @Test - void usesRootMappingOfTargetClassForMethodsOfParent() throws Exception { - - Method method = ParentControllerWithoutRootMapping.class.getMethod("someEmptyMappedMethod"); - - Link link = linkTo(ChildControllerWithRootMapping.class, method).withSelfRel(); - assertThat(link.getHref()).endsWith("/root"); - } - - /** - * @see #257, #107 - */ - @Test - void usesXForwardedProtoHeaderAsLinkSchema() { - - for (String proto : Arrays.asList("http", "https")) { - - setUp(); - request.addHeader("X-Forwarded-Proto", proto); - - adaptRequestFromForwardedHeaders(); - - Link link = linkTo(PersonControllerImpl.class).withSelfRel(); - assertThat(link.getHref()).startsWith(proto + "://"); - } - } - - /** - * @see #257, #107 - */ - @Test - void usesProtoValueFromForwardedHeaderAsLinkSchema() { - - for (String proto : Arrays.asList("http", "https")) { - - setUp(); - request.addHeader("Forwarded", new String[] { "proto=" + proto }); - - adaptRequestFromForwardedHeaders(); - - Link link = linkTo(PersonControllerImpl.class).withSelfRel(); - assertThat(link.getHref()).startsWith(proto.concat("://")); - } - } - - /** - * @see #257, #107 - */ - @Test - void favorsStandardForwardHeaderOverXForwardedProto() { - - request.addHeader("X-Forwarded-Proto", "foo"); - request.addHeader("Forwarded", "proto=bar"); - - adaptRequestFromForwardedHeaders(); - - Link link = linkTo(PersonControllerImpl.class).withSelfRel(); - assertThat(link.getHref()).startsWith("bar://"); - } - - /** - * @see #331 - */ - @Test - void linksToMethodWithRequestParamImplicitlySetToFalse() { - - Link link = linkTo(methodOn(ControllerWithMethods.class).methodForOptionalSizeWithDefaultValue(null)).withSelfRel(); - - assertThat(link.getHref()).endsWith("/bar"); - } - - /** - * @see #398 - */ - @Test - void encodesRequestParameterWithSpecialValue() { - - Link link = linkTo(methodOn(ControllerWithMethods.class).methodWithRequestParam("Spring#\n")).withSelfRel(); - - assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF); - assertThat(link.getHref()).endsWith("/something/foo?id=Spring%23%0A"); - } - - /** - * @see #169 - */ - @Test - void createsPartiallyExpandedLink() { - - Link link = linkTo(methodOn(PersonsAddressesController.class, "some id").getAddressesForCountry(null)) - .withSelfRel(); - - assertThat(link.isTemplated()).isTrue(); - assertThat(link.getHref()).contains("some%20id"); - } - - /** - * @see #169 - */ - @Test - void addsRequestParameterVariablesForMissingRequiredParameter() { - - assertThatIllegalArgumentException().isThrownBy(() -> { - Link link = linkTo(methodOn(ControllerWithMethods.class).methodForNextPage("1", 10, null)).withSelfRel(); - - assertThat(link.getVariableNames()).containsExactly("limit"); - - link.expand(); - }).withMessageContaining("limit"); - } - - /** - * @see #169 - */ - @Test - void addsOptionalRequestParameterTemplateForMissingValue() { - - Link link = linkTo(methodOn(ControllerWithMethods.class).methodForNextPage("1", null, 5)).withSelfRel(); - - assertThat(link.getVariables()) - .containsExactly(new TemplateVariable("offset", VariableType.REQUEST_PARAM_CONTINUED)); - - UriComponents components = toComponents(link); - - assertThat(components.getQueryParams().get("query")).isNull(); - } - - /** - * @see #509 - */ - @Test - void supportsTwoProxiesAddingXForwardedPort() { - - request.addHeader("X-Forwarded-Port", "1443,8443"); - request.addHeader("X-Forwarded-Host", "proxy1,proxy2"); - - adaptRequestFromForwardedHeaders(); - - assertThat(linkTo(PersonControllerImpl.class).withSelfRel().getHref()).startsWith("http://proxy1:1443"); - } - - /** - * @see #509 - */ - @Test - void resolvesAmbiguousXForwardedHeaders() { - - request.addHeader("X-Forwarded-Proto", "http"); - request.addHeader("X-Forwarded-Ssl", "on"); - - assertThat(linkTo(PersonControllerImpl.class).withSelfRel().getHref()).startsWith("http://"); - } - - /** - * @see #527 - */ - @Test - void createsLinkRelativeToContextRoot() { - - request.setContextPath("/ctx"); - request.setServletPath("/foo"); - request.setRequestURI("/ctx/foo"); - - assertThat(linkTo(PersonControllerImpl.class).withSelfRel().getHref()).endsWith("/ctx/people"); - } - - /** - * @see #639 - */ - @Test - void considersEmptyOptionalMethodParameterOptional() { - - Link link = linkTo(methodOn(ControllerWithMethods.class).methodWithJdk8Optional(Optional.empty())).withSelfRel(); - - assertThat(link.isTemplated()).isTrue(); - assertThat(link.getVariableNames()).containsExactly("value"); - } - - /** - * @see #639 - */ - @Test - void considersOptionalWithValueMethodParameterOptional() { - - Link link = linkTo(methodOn(ControllerWithMethods.class).methodWithJdk8Optional(Optional.of(1))).withSelfRel(); - - assertThat(link.isTemplated()).isFalse(); - assertThat(link.getHref()).endsWith("?value=1"); - } - - /** - * @see #617 - */ - @Test - void alternativePathVariableParameter() { - - Link link = linkTo(methodOn(ControllerWithMethods.class).methodWithAlternatePathVariable("bar")).withSelfRel(); - assertThat(link.getHref()).isEqualTo("http://localhost/something/bar/foo"); - } - - private static UriComponents toComponents(Link link) { - return UriComponentsBuilder.fromUriString(link.expand().getHref()).build(); - } - - static class Person { - Long id; - } - - @RequestMapping("/people") - interface PersonController {} - - class PersonControllerImpl implements PersonController {} - - @RequestMapping("/people/{id}/addresses") - static class PersonsAddressesController { - - @RequestMapping("/{country}") - public HttpEntity getAddressesForCountry(@PathVariable String country) { - return null; - } - } - - @RequestMapping({ "/persons", "/people" }) - class InvalidController { - - } - - class UnmappedController { - - } - - @RequestMapping("/something") - static class ControllerWithMethods { - - @RequestMapping("/else") - HttpEntity myMethod(@RequestBody Object payload) { - return null; - } - - @RequestMapping("/{id}/foo") - HttpEntity methodWithPathVariable(@PathVariable String id) { - return null; - } - - @RequestMapping("/foo") - HttpEntity methodWithRequestParam(@RequestParam String id) { - return null; - } - - @RequestMapping(value = "/{id}/foo") - HttpEntity methodForNextPage(@PathVariable String id, @RequestParam(required = false) Integer offset, - @RequestParam Integer limit) { - return null; - } - - @RequestMapping(value = "/{id}/foo") - HttpEntity methodWithMultiValueRequestParams(@PathVariable String id, @RequestParam List items, - @RequestParam Integer limit) { - return null; - } - - @RequestMapping(value = "/{id}/foo") - HttpEntity methodWithAlternatePathVariable(@PathVariable(name = "id") String otherId) { - return null; - } - - @RequestMapping(value = "/foo") - HttpEntity methodForOptionalNextPage(@RequestParam(required = false) Integer offset) { - return null; - } - - @RequestMapping(value = "/bar") - HttpEntity methodForOptionalSizeWithDefaultValue(@RequestParam(defaultValue = "10") Integer size) { - return null; - } - - @RequestMapping - HttpEntity methodWithJdk8Optional(@RequestParam Optional value) { - return null; - } - } - - @RequestMapping("/parent") - interface ParentController {} - - interface ChildController extends ParentController { - - @RequestMapping("/child") - Object myMethod(); - } - - interface ParentWithMethod { - - @RequestMapping("/parent") - Object myMethod(); - } - - @RequestMapping("/child") - interface ChildWithTypeMapping extends ParentWithMethod {} - - interface ParentControllerWithoutRootMapping { - - @RequestMapping - Object someEmptyMappedMethod(); - } - - @RequestMapping("/root") - interface ChildControllerWithRootMapping extends ParentControllerWithoutRootMapping { - - } -}