Skip to content
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

Error using List as @RequestParam #162

Closed
Juchar opened this issue Jun 21, 2018 · 7 comments
Closed

Error using List as @RequestParam #162

Juchar opened this issue Jun 21, 2018 · 7 comments
Assignees
Labels

Comments

@Juchar
Copy link

Juchar commented Jun 21, 2018

  • Framework version: 1.1
  • Implementations: Spring Boot

Scenario

Using List<T> as a @RequestParam and executing the request /test?list=1,2,3.

Expected behavior

Executing the request locally by starting Spring Boot the list is filled correctly.

Actual behavior

An exception occurs.

Steps to reproduce

Implement the following method in a controller:

@RequestMapping(path = "test", produces = MediaType.APPLICATION_JSON_VALUE)
public String test(List<String> list) {}

sam.yml:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: My Description
Resources:
  MyServiceFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: com.example.StreamLambdaHandler::handleRequest
      Runtime: java8
      CodeUri: target/example.jar
      MemorySize: 512
      Policies: AWSLambdaBasicExecutionRole
      Timeout: 30
      Events:
        GetResource:
          Type: Api
          Properties:
            Path: /{proxy+}
            Method: GET

Outputs:
  ExampleAPI:
    Description: URL for application
    Value: !Sub 'https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/test'
    Export:
      Name: ExampleAPI

Execute:
/test?list=1,2,3 or /test?list=1&list=2&list=3 on the Lambda URL.

Full log output

2018-06-21 05:24:28.706 ERROR 1 --- [ main] o.s.boot.web.support.ErrorPageFilter : Forwarding to error page from request [/test] due to exception [Failed to instantiate [java.util.List]: Specified class is an interface]
org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.util.List]: Specified class is an interface
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:99) ~[task/:na]
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.createAttribute(ModelAttributeMethodProcessor.java:141) ~[task/:na]
at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttribute(ServletModelAttributeMethodProcessor.java:81) ~[task/:na]
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:101) ~[task/:na]
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[task/:na]
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:158) ~[task/:na]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128) ~[task/:na]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[task/:na]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[task/:na]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[task/:na]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[task/:na]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[task/:na]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[task/:na]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[task/:na]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[task/:na]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687) ~[task/:na]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[task/:na]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) ~[task/:na]
at com.amazonaws.serverless.proxy.internal.servlet.FilterChainManager$ServletExecutionFilter.doFilter(FilterChainManager.java:351) ~[task/:na]
at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:84) [task/:na]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[task/:na]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [task/:na]
at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:84) [task/:na]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105) ~[task/:na]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [task/:na]
at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:84) [task/:na]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[task/:na]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [task/:na]
at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:84) [task/:na]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[task/:na]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [task/:na]
at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:84) [task/:na]
at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:115) [task/:na]
at org.springframework.boot.web.support.ErrorPageFilter.access$000(ErrorPageFilter.java:59) [task/:na]
at org.springframework.boot.web.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:90) [task/:na]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [task/:na]
at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:108) [task/:na]
at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:84) [task/:na]
at com.amazonaws.serverless.proxy.internal.servlet.AwsLambdaServletContainerHandler.doFilter(AwsLambdaServletContainerHandler.java:207) [task/:na]
at com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler.handleRequest(SpringBootLambdaContainerHandler.java:154) [task/:na]
at com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler.handleRequest(SpringBootLambdaContainerHandler.java:52) [task/:na]
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxy(LambdaContainerHandler.java:168) [task/:na]
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxyStream(LambdaContainerHandler.java:200) [task/:na]
at com.example.StreamLambdaHandler.handleRequest(StreamLambdaHandler.java:30) [task/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_141]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_141]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_141]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_141]
at lambdainternal.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:350) [LambdaSandboxJava-1.0.jar:na]
at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:888) [LambdaSandboxJava-1.0.jar:na]
at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:283) [LambdaSandboxJava-1.0.jar:na]
at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:64) [LambdaSandboxJava-1.0.jar:na]
at java.lang.Class.forName0(Native Method) [na:1.8.0_141]
at java.lang.Class.forName(Class.java:348) [na:1.8.0_141]
at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:94) [LambdaJavaRTEntry-1.0.jar:na]
@sapessi
Copy link
Collaborator

sapessi commented Jun 21, 2018

Hey @Juchar, the exception thrown says that Spring cannot instantiate a List - rightly so, because List is an interface. Have you tried declaring the parameter as an implementation of List? For example ArrayList?

@Juchar
Copy link
Author

Juchar commented Jun 22, 2018

@sapessi
Hey, that was my intention too, so I debugged a little bit further. Adding @RequestParam to the parameter solves the issue when using it locally (by executing Spring Boot), then everything works out, no instantiation errors while still keeping the List<> interface.

Additionally I also updated the library to 1.1.1.

Now I do not have an error anymore, but the result is also not correct:

  • Executing the request /test?list=1&list=2&list=3 on AWS Lambda I now get a list with only one entry: [3]
  • Executing the request /test?list=1,2,3 on AWS Lambda I now get a list with only one entry: [1%2C2%2C3]

@sapessi
Copy link
Collaborator

sapessi commented Jun 22, 2018

Hey @Juchar, the first issue is expected. It's caused by the fact that API Gateway uses a simple Map to send query string parameters to Lambda - for this reason the parameter list only contains the last value that was read for it.

In the second case, it looks like Spring is not URLDecoding the parameter before trying to read it as a list. This is a change we made for version 1.1.1, fixes things with Jersey but looks like it may be causing an issue with Spring. I'll investigate and if needed publish a fix today.

@sapessi
Copy link
Collaborator

sapessi commented Jun 22, 2018

Sigh, it does indeed look like a bug. I'll work on it and publish a 1.1.3 later today. I'll resolve this tickets once it's out.

@sapessi sapessi self-assigned this Jun 22, 2018
@sapessi sapessi added the bug label Jun 22, 2018
sapessi added a commit that referenced this issue Jun 22, 2018
…me from request decoded. the getQueryString return an encoded string.
@sapessi
Copy link
Collaborator

sapessi commented Jun 22, 2018

Hey @Juchar, could you test with 1.2-SNAPSHOT in the core branch of this repo?

@sapessi
Copy link
Collaborator

sapessi commented Jun 22, 2018

@Juchar, Release 1.1.3 is making its way to maven central and it should fix this issue. Feel free to re-open this if you still run into problems. As I said API Gateway uses a simple Map to send query string parameters to Lambda - for this reason you cannot have multiple query string parameters with the same name as a list.

@sapessi sapessi closed this as completed Jun 22, 2018
@Juchar
Copy link
Author

Juchar commented Jun 25, 2018

@sapessi Did not have the time on the weekend but just tried it out and it seems that everything works. Thank you for the quick solution! Great support!

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

No branches or pull requests

2 participants