Skip to content

Issue creating Link from linkTo when using function that has Generic parameters #436

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Maraket opened this issue Feb 20, 2016 · 5 comments

Comments

@Maraket
Copy link

Maraket commented Feb 20, 2016

I am currently working on a small self development project, and expanding a standard JSON style controller with CRUD capabilities. to become more capable through the HATOAS that has been brilliantly developed. I've based some of my design off of http://spring.io/guides/tutorials/bookmarks/ though taken a bit of time to expand it and making it a little smarter. So the issue I am facing is when I try to add the link to the class that extends ResourceSupport like below (note controller is a Class object that is passed to my object in the constructor):

this.add(linkTo(methodOn(controller).get(commonObject.getId())).withSelfRel());

The following exception and stacktrace is thrown:

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [@org.springframework.web.bind.annotation.RequestParam ?] to type [java.lang.String] at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:313) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.hateoas.mvc.AnnotatedParametersParameterAccessor$BoundMethodParameter.asString(AnnotatedParametersParameterAccessor.java:172) ~[spring-hateoas-0.19.0.RELEASE.jar:na] at org.springframework.hateoas.mvc.ControllerLinkBuilderFactory.bindRequestParameters(ControllerLinkBuilderFactory.java:214) ~[spring-hateoas-0.19.0.RELEASE.jar:na] at org.springframework.hateoas.mvc.ControllerLinkBuilderFactory.linkTo(ControllerLinkBuilderFactory.java:136) ~[spring-hateoas-0.19.0.RELEASE.jar:na] at org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo(ControllerLinkBuilder.java:138) ~[spring-hateoas-0.19.0.RELEASE.jar:na] at com.platform.common.hateoas.CommonResource.<init>(CommonResource.java:22) ~[classes/:na] at com.platform.common.abstracts.AbstractCRUDController.add(AbstractCRUDController.java:79) ~[classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_60] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_60] at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_60] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222) [spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) [spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:871) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:648) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:65) [spring-test-4.2.4.RELEASE.jar:4.2.4.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167) [spring-test-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134) [spring-test-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:155) [spring-test-4.2.4.RELEASE.jar:4.2.4.RELEASE] at test.platform.controller.CommonPatternControllerTest.goodAdd(CommonPatternControllerTest.java:143) [test-classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_60] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_60] at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_60] at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) [junit-4.12.jar:4.12] at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12] at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) [junit-4.12.jar:4.12] at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) [junit-4.12.jar:4.12] at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) [junit-4.12.jar:4.12] at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) [spring-test-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) [junit-4.12.jar:4.12] at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) [spring-test-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) [spring-test-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) [junit-4.12.jar:4.12] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:254) [spring-test-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89) [spring-test-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12] at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) [junit-4.12.jar:4.12] at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) [junit-4.12.jar:4.12] at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) [spring-test-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193) [spring-test-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) [.cp/:na]

The function in question it is having issues mapping has the following signature:

public ResponseEntity<?> get(@PathVariable("id") K id)

Where K extends Serializable and this is then defined in the parent class as an Integer. I've found when changing this to Integer it runs just fine, but since I'm trying to make my controllers flexible by using the generics I'd prefer to avoid using solid datatypes until I extend the class. I found it weird that when I used the methodOn on other functions that used @RequestBody it didnt seem to mind.

Is this intentional, as I would think since the controller class passed to it is defined already since its extended.

@odrotbohm
Copy link
Member

Any chance you post the relevant parts of the generics signatures including the method or class that actually defines the generic type? I guess we might be looking at the declared method not the one that virtually ends up in the class that then fixes the generic parameter.

One thin that caught my eye though is that the signature you show uses @PathVariable and the exception complains about a parameter using @RequestParam. So the exception is definitely caused by a different method.

@Maraket
Copy link
Author

Maraket commented Feb 20, 2016

So this is the code of my abstract controller (Ommiting other functions)

public abstract class AbstractCRUDController<K extends Serializable, T extends AbstractRawDbObject<K>> {
@RequestMapping(value = { "/{id}" }, method = RequestMethod.GET)
    public ResponseEntity<?> get(@PathVariable("id") K id) {
        try {
            T output = repo.findOne(id);
            if (output == null)
                return new ResponseEntity<String>(errorMessage(output, ACTION.GET), HttpStatus.BAD_REQUEST);

            // return new CommonResource<K, T>(output,getControllerClass());
            return new ResponseEntity<T>(output, HttpStatus.OK);
        } catch (Exception ex) {
            log.error(logMessage(ACTION.GET), ex);
            return new ResponseEntity<String>(errorMessage(ACTION.GET), HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}

And the exception thrown is either @RequestParam or @PathVariable depending on which I use. I changed it back from @PathVariable and didn't notice. Sorry for the confusion

@oferrero
Copy link

oferrero commented Mar 1, 2016

I'm running into the same issue. Seems to be the same as: #352

@nickthomas6
Copy link

Is there a work around for this?

@sigint76
Copy link

Any news, I'm running the same problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants