diff --git a/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactory.java b/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactory.java index 3a48f4d29..9850ed419 100644 --- a/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactory.java +++ b/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactory.java @@ -30,9 +30,12 @@ import java.util.List; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.MethodParameter; import org.springframework.hateoas.Link; import org.springframework.hateoas.MethodLinkBuilderFactory; +import org.springframework.hateoas.ResourceSupport; import org.springframework.hateoas.TemplateVariable; import org.springframework.hateoas.TemplateVariables; import org.springframework.hateoas.core.AnnotationAttribute; @@ -44,6 +47,7 @@ import org.springframework.hateoas.core.MethodParameters; import org.springframework.hateoas.mvc.AnnotatedParametersParameterAccessor.BoundMethodParameter; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -67,6 +71,8 @@ */ public class ControllerLinkBuilderFactory implements MethodLinkBuilderFactory { + private static final Logger log = LoggerFactory.getLogger(ControllerLinkBuilderFactory.class); + private static final MappingDiscoverer DISCOVERER = new AnnotationMappingDiscoverer(RequestMapping.class); private static final AnnotatedParametersParameterAccessor PATH_VARIABLE_ACCESSOR = new AnnotatedParametersParameterAccessor( new AnnotationAttribute(PathVariable.class)); @@ -135,6 +141,20 @@ public ControllerLinkBuilder linkTo(Object invocationValue) { Iterator classMappingParameters = invocations.getObjectParameters(); Method method = invocation.getMethod(); + if (!ClassUtils.isAssignable(ResourceSupport.class, method.getReturnType())) { + log.warn(""); + log.warn(method.getDeclaringClass().getSimpleName() + "." + method.getName() + "()'s return type is " + method.getReturnType().toString() + ", which doesn't implement ResourceSupport, Resource, or Resources."); + log.warn("Return that from a controller and it probably won't serialize correctly."); + log.warn(""); + + System.out.println(""); + System.out.println(method.getDeclaringClass().getSimpleName() + "." + method.getName() + "()'s return type is " + method.getReturnType().toString() + ", which doesn't implement ResourceSupport, Resource, or Resources."); + System.out.println("Return that from a controller and it probably won't serialize correctly."); + System.out.println(""); + + throw new RuntimeException(method.getReturnType().toString() + " does NOT implement ResourceSupport"); + } + String mapping = DISCOVERER.getMapping(invocation.getTargetType(), method); UriComponentsBuilder builder = ControllerLinkBuilder.getBuilder().path(mapping); diff --git a/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactoryUnitTest.java b/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactoryUnitTest.java index 8989e885c..dfe41fb2e 100644 --- a/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactoryUnitTest.java +++ b/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactoryUnitTest.java @@ -31,6 +31,7 @@ import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat.ISO; import org.springframework.hateoas.Link; +import org.springframework.hateoas.Resource; import org.springframework.hateoas.TestUtils; import org.springframework.hateoas.mvc.ControllerLinkBuilderUnitTest.ControllerWithMethods; import org.springframework.hateoas.mvc.ControllerLinkBuilderUnitTest.PersonControllerImpl; @@ -174,19 +175,19 @@ public void createsLinkToParameterizedControllerRootWithParameterMap() { assertThat(link.getHref(), endsWith("/people/17/addresses")); } - static interface SampleController { + interface SampleController { @RequestMapping("/sample/{id}") - HttpEntity sampleMethod(@PathVariable("id") Long id, SpecialType parameter); + Resource> sampleMethod(@PathVariable("id") Long id, SpecialType parameter); @RequestMapping("/sample/{time}") - HttpEntity sampleMethod(@PathVariable("time") @DateTimeFormat(iso = ISO.DATE) DateTime time); + Resource> sampleMethod(@PathVariable("time") @DateTimeFormat(iso = ISO.DATE) DateTime time); @RequestMapping("/sample/mapsupport") - HttpEntity sampleMethodWithMap(@RequestParam Map queryParams); + Resource> sampleMethodWithMap(@RequestParam Map queryParams); @RequestMapping("/sample/multivaluemapsupport") - HttpEntity sampleMethodWithMap(@RequestParam MultiValueMap queryParams); + Resource> sampleMethodWithMap(@RequestParam MultiValueMap queryParams); } static class SampleUriComponentsContributor implements UriComponentsContributor { diff --git a/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderUnitTest.java b/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderUnitTest.java index ab16a086d..7ddd620a7 100644 --- a/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderUnitTest.java +++ b/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderUnitTest.java @@ -30,6 +30,7 @@ import org.mockito.Mockito; import org.springframework.hateoas.Identifiable; import org.springframework.hateoas.Link; +import org.springframework.hateoas.Resource; import org.springframework.hateoas.TemplateVariable; import org.springframework.hateoas.TemplateVariable.VariableType; import org.springframework.hateoas.TestUtils; @@ -577,7 +578,7 @@ class PersonControllerImpl implements PersonController {} static class PersonsAddressesController { @RequestMapping("/{country}") - public HttpEntity getAddressesForCountry(@PathVariable String country) { + public Resource> getAddressesForCountry(@PathVariable String country) { return null; } } @@ -595,39 +596,39 @@ class UnmappedController { static class ControllerWithMethods { @RequestMapping("/else") - HttpEntity myMethod(@RequestBody Object payload) { + Resource> myMethod(@RequestBody Object payload) { return null; } @RequestMapping("/{id}/foo") - HttpEntity methodWithPathVariable(@PathVariable String id) { + Resource> methodWithPathVariable(@PathVariable String id) { return null; } @RequestMapping("/foo") - HttpEntity methodWithRequestParam(@RequestParam String id) { + Resource> methodWithRequestParam(@RequestParam String id) { return null; } @RequestMapping(value = "/{id}/foo") - HttpEntity methodForNextPage(@PathVariable String id, @RequestParam(required = false) Integer offset, + Resource> 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, + Resource> methodWithMultiValueRequestParams(@PathVariable String id, @RequestParam List items, @RequestParam Integer limit) { return null; } @RequestMapping(value = "/foo") - HttpEntity methodForOptionalNextPage(@RequestParam(required = false) Integer offset) { + Resource> methodForOptionalNextPage(@RequestParam(required = false) Integer offset) { return null; } @RequestMapping(value = "/bar") - HttpEntity methodForOptionalSizeWithDefaultValue(@RequestParam(defaultValue = "10") Integer size) { + Resource> methodForOptionalSizeWithDefaultValue(@RequestParam(defaultValue = "10") Integer size) { return null; } } @@ -638,13 +639,13 @@ interface ParentController {} interface ChildController extends ParentController { @RequestMapping("/child") - Object myMethod(); + Resource myMethod(); } interface ParentWithMethod { @RequestMapping("/parent") - Object myMethod(); + Resource myMethod(); } @RequestMapping("/child") @@ -653,7 +654,7 @@ interface ChildWithTypeMapping extends ParentWithMethod {} interface ParentControllerWithoutRootMapping { @RequestMapping - Object someEmptyMappedMethod(); + Resource someEmptyMappedMethod(); } @RequestMapping("/root") diff --git a/src/test/java/org/springframework/hateoas/mvc/DummyInvocationUtilsUnitTest.java b/src/test/java/org/springframework/hateoas/mvc/DummyInvocationUtilsUnitTest.java index a4f4234cb..50cbd5a0d 100644 --- a/src/test/java/org/springframework/hateoas/mvc/DummyInvocationUtilsUnitTest.java +++ b/src/test/java/org/springframework/hateoas/mvc/DummyInvocationUtilsUnitTest.java @@ -16,6 +16,7 @@ package org.springframework.hateoas.mvc; import org.junit.Test; +import org.springframework.hateoas.Resource; import org.springframework.hateoas.TestUtils; import org.springframework.hateoas.core.DummyInvocationUtils; import org.springframework.http.HttpEntity; @@ -40,8 +41,8 @@ public void test() { static class SampleController { @RequestMapping("/{id}/foo") - HttpEntity someMethod(@PathVariable("id") Long id) { - return new ResponseEntity(HttpStatus.OK); + Resource> someMethod(@PathVariable("id") Long id) { + return new Resource(new ResponseEntity(HttpStatus.OK)); } } } diff --git a/template.mf b/template.mf index d42f75844..e37abf5e0 100644 --- a/template.mf +++ b/template.mf @@ -13,4 +13,5 @@ Import-Template: org.aopalliance.*;version="[1.0.0,2.0.0)";resolution:=optional, org.atteo.evo.inflector.*;version="${evo.version:[=.=.=,+1.0.0)}";resolution:=optional, org.springframework.plugin.*;version="[0.8.0,2.0.0)";resolution:=optional, - org.springframework.*;version="${spring.version:[=.=.=,+1.1.0)}";resolution:=optional + org.springframework.*;version="${spring.version:[=.=.=,+1.1.0)}";resolution:=optional, + org.slf4j.*;version="[1.7.22,1.7.22]";resolution:=optional