2

Background

I have a list of strings (records) that are dynamically created by a class. Each record may have different keys (e.g. favorite_pizza on first, favorite_candy on second).

// Note: These records are dynamically created and not stored
// in this way. This is simply for display purposes.
List<String> records =
    Arrays.asList(
        "{\"name\":\"Bob\",\"age\":40,\"favorite_pizza\":\"Cheese\"}",
        "{\"name\":\"Jill\",\"age\":22,\"favorite_candy\":\"Swedish Fish\"}");

The list of records is then passed to a separate HTTP request class.

public Response addRecords(List<String> records) {
    ...
}

Inside the HTTP request service, I want to build a JSON request body:

{
  "records": [
    {
      "name": "Bob",
      "age": 40,
      "favorite_pizza": "Cheese"
    },
    {
      "name": "Jill",
      "age": 22,
      "favorite_candy": "Swedish Fish"
    }
  ]
}

I'm using org.json.JSONObject to add the records key and create the request body:

JSONObject body = new JSONObject();

// Add the "records" key
body.put("records", records);

// Create the request body
body.toString();

Issues

When I run my junit test in IntelliJ, the request body contains a backslash before each quote:

org.junit.ComparisonFailure: 
Expected :"{"records":["{"name":"Bob","age":40,"favorite_pizza":"Cheese"}","{"name":"Jill","age":22,"favorite_candy":"Swedish Fish"}"]}"
Actual   :"{"records":["{\"name\":\"Bob\",\"age\":40,\"favorite_pizza\":\"Cheese\"}","{\"name\":\"Jill\",\"age\":22,\"favorite_candy\":\"Swedish Fish\"}"]}"

And when I make the request it fails because the body is not formatted correctly:

{
  "records": [
    "{\"name\":\"Bob\",\"age\":40,\"favorite_pizza\":\"Cheese\"}",
    "{\"name\":\"Jill\",\"age\":22,\"favorite_candy\":\"Swedish Fish\"}"
  ]
}

Questions

  • Why is JSONObject including the backslashes before each quote?
  • How do I remove the backslashes?
Ryan Payne
  • 5,249
  • 4
  • 28
  • 69

2 Answers2

4

You are creating a list of string, which is not what you want.

You should instead create a list of objects (Maps)

Map<String, Object> m1 = new LinkedHashMap<>();
m1.put("name", "Bob");
m1.put("age", 40);
m1.put("favorite_pizza", "Cheese");

LinkedHashMap<String, Object> m2 = new LinkedHashMap<>();
m2.put("name", "Jill");
m2.put("age", 22);
m2.put("favorite_candy", "Swedish Fish");
List<LinkedHashMap<String, Object>> records = Arrays.asList(m1,m2);

JSONObject body = new JSONObject();

// Add the "records" key
body.put("records", records);

This is a quite common mistake (it seems), to try to serialize strings formatted like json objects expecting is the same thing as passing a the object itself.

UPDATE:

Or if you have a json serialized object list then ...

List<String> recordSource =
    Arrays.asList(
        "{\"name\":\"Bob\",\"age\":40,\"favorite_pizza\":\"Cheese\"}",
        "{\"name\":\"Jill\",\"age\":22,\"favorite_candy\":\"Swedish Fish\"}");
List<JSONObject> records =
    recordSource.stream().map(JSONObject::new).collect(Collectors.toList());

JSONObject body = new JSONObject();

// Add the "records" key
body.put("records", records);
System.out.println(body.toString());
Ryan Payne
  • 5,249
  • 4
  • 28
  • 69
minus
  • 2,646
  • 15
  • 18
  • Thanks @minus. Unfortunately, the list of strings is dynamically created and passed to this class—the HTTP request service—so I can't implement your suggestion. – Ryan Payne Aug 23 '19 at 15:26
  • 1
    Then you should parse the string into a Map and then add the map to your list. – minus Aug 23 '19 at 15:27
  • I've updated my question to more closely reflect the context I am dealing with. Could you please update your example based on your latest suggestion ("parse the string into a Map and then add the map to your list")? I'm having trouble visualizing the implementation. – Ryan Payne Aug 23 '19 at 15:33
0

If your record strings are already valid json you can either

  1. Iterate over them, converting them one at a time into a JSONObject (see here) and then add the result to a JSONArray which you can manipulate if needed.

  2. Create the array entirely by hand since it's just comma separated record strings inside square brackets.

geco17
  • 5,152
  • 3
  • 21
  • 38