5

I am creating an API (written in Java) which I am deploying through serverless which ports to a AWS Lambda function. All aspects of the API function great except for the fact that the requests which are returned include the '\' character in front of all quotes.

To put this into perspective, I have a person class which contains instance variables for name (String) and mood (String). I then have my class which uses this class to get and create a Person object, and then Jackson is used to parse this into JSON format. This is what is returned to the handler function (for lambda) and is displayed as the "object body".

public class Person{
    String name;
    String mood;
    //getters and setters and constructor
}

Then, later on there will be something in a different class like

Person person = new Person("bob", "good");

Which would be passed into my method which is supposed to convert things to JSON:

private String convStrToJson(Person person) throws JsonProcessingException {

    ObjectMapper mapper = new ObjectMapper();
    String json = mapper.writeValueAsString(person);
    return json;

}

If I were to print this in the output, I'd get something like:

{"name":"bob","mood":"good"}

Which is what I want and expect. However, when deployed and called via GET request, the result is:

"{\"name\":\"bob\",\"mood\":\"good\"}"

I've tried several strategies, including additions to the parsing method such as:

json = json.replace("\"", "");

Which removes the quotes fully from both outputs, or:

json = json.replace("\\","");

Which has no effect at all. I also tried both of these as replaceAll methods and that just messed things up even more. I'm not sure what else I can do to get rid of these '\' characters, I understand why they're there but I don't know how to stop that. Any assistance is appreciated.

6
  • Are you performing get request from client side/javascript? If yes, you can use JSON.parse(json) Commented Dec 13, 2017 at 4:15
  • I mean technically the GET request is performed from the client side, however its just being invoked by calling the AWS-generated URL at the moment and so there is no Javascript configuration behind it that I've written :/ It seems to me that for some reason when AWS outputs the data it includes all aspects of the String including any escape characters, so far I still can't find a work around :/ @JayIbe Commented Dec 13, 2017 at 20:26
  • 1
    You're trying to solve the wrong problem. This is a JSON object re-encoded as a JSON string. You need to identify the source of the double-encoding. Commented Dec 14, 2017 at 1:18
  • The only source I can identify is AWS, there is no double encoding issues within the code itself (if I print the data to the console it looks great) so therefore I cannot fix the issue within the code. Unfortunately, I have realised this. However, when the information is returned via Lambda to API Gateway, AWS requires it already be parsed into JSON, which the code does flawlessly. Somewhere in the deployment process AWS must be parsing the JSON Object into a String including (somehow) the '\' characters. The problem is I don't know where, or how I can change this @Michael-sqlbot Commented Dec 14, 2017 at 22:25
  • "called via GET request" how? You're saying Lambda returns what you expect to API Gateway (confirmed by logs) but then API Gateway returns this as the double-encoded form to the caller? Commented Dec 15, 2017 at 4:02

3 Answers 3

5

Okay so I figured it out. Turns out serverless not only includes Jackson, but actually in the layout it creates for handling responses, the "setObjectBody" section will accept any kind of object and use Jackson to parse it to JSON. This is where I messed up. I assumed it would only accept Strings, which is where the double encoding was occurring. Now, if I pass in the Person object, serverless/Jackson handles it appropriately for me and the expected output is returned. I'll include code snippets below to better demonstrate this solution. Serverless creates a 'handler' class which has a template including a method called handleRequest. Once filled in, this class now looks like this:

public class GetStatusHandler implements RequestHandler<Map<String, Object>, ApiGatewayResponse> {

private static final Logger LOG = Logger.getLogger(GetStatusHandler.class);

@SuppressWarnings("unchecked")
public ApiGatewayResponse handleRequest(Map<String, Object> input, Context context) {

    BasicConfigurator.configure();

    LOG.info("received: " + input);

      try {

         Map<String, String> pathParameters = (Map<String, String>) input.get("queryStringParameters");

         if(pathParameters == null) {

             LOG.info("Getting details for all persons ");
              PersonControl control = new PersonControl();
              Person[] result = control.myGetHandler(context); 
              return ApiGatewayResponse.builder()
                        .setStatusCode(200)
                        .setObjectBody(result)
                        .setHeaders(Collections.singletonMap("X-Powered-By", "AWS Lambda & serverless"))
                        .build();

         }else {

             String name = pathParameters.get("name"); 
             LOG.info("Getting details for "+name);
             PersonControl control = new PersonControl();
             Person result = control.myGetHandler(name, context);
             return ApiGatewayResponse.builder()
                        .setStatusCode(200)
                        .setObjectBody(result)
                        .setHeaders(Collections.singletonMap("X-Powered-By", "AWS Lambda & serverless"))
                        .build();

         }


        }catch(Exception e) {

            LOG.error(e, e);
            Response responseBody = new Response("Failure getting person", null);

            return ApiGatewayResponse.builder()
                  .setStatusCode(500)
                  .setObjectBody(responseBody)
                  .setHeaders(Collections.singletonMap("X-Powered-By", "AWS Lambda & serverless"))
                  .build();
        }
    }
}

Not that when returning the ApiGatewayResponse (via builder), an object is simply passed in to the .setObjectBody method ('result') which serverless automatically converts to JSON for us. Thats it! No parsing to JSON necessary in the code.

Sign up to request clarification or add additional context in comments.

1 Comment

hi @koko985 would you mind telling me what did you import or how is your pom to be able to use ApiGatewayResponse? I am unable to find anything, even though I found the git project with the code
1

The response can be a user defined object as below

class Handler implements RequestHandler<SQSEvent, CustomObject> {
    public CustomObject handleRequest(SQSEvent event, Context context) {
        return new CustomObject();
    }
}

Sample code can be found here.

Comments

-2

Just use the Google Gson java library that can be used to convert Java Objects into their JSON representation.

Gson gson = new Gson();
gson.toJson(person);

1 Comment

Unfortunately I have tried this approach but it does not help the issue as the problem isn't parsing, but how AWS/Lambda handles the parsed Strings. Using Gson gives the same result as using Jackson.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.