20

I have a string that is in Json format, only none of the keys or values are surrounded by quotes. For example, I have this:

String json = "{name: Bob, state: Colorado, Friends: [{ name: Dan, age: 23 }, {name: Zane, age: 24 }]}"

I want this to become a map that looks like so:

Map<String, Object> friend1Map = new HashMap<>();
friend1Map.put("name", "Dan");
friend1Map.put("age", 23);

Map<String, Object> friend2Map = new Hashmap<>();
friend2Map.put("name", "Zane");
friend2Map.put("age", 24);

Map<String, Object> newMap = new HashMap<>();
newMap.put("name", "Bob");
newMap.put("state", "Colorado");
newMap.put("Friends", Arrays.asList(friend1Map, friend2Map));

I have tried the following two methods:

ObjectMapper mapper = new ObjectMapper();
mapper.readValue(json, new TypeReference<Map<String, Object>>() {});

This will throw an error, saying:

Unexpected character ('n'): was expecting double-quote to start field name

Then I tried changing the config of mapper:

mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
mapper.readValue(json, new TypeReference<Map<String, Object>>() {});

But this threw an error saying:

com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'Bob': was expecting ('true', 'false' or 'null')
at [Source: {name: Bob, state: Colorado, Friends: [{ name: Dan, age: 23 }, {name: Zane, age: 24 }]}; line: 1, column: 11]

Is there a way of getting this Map when quotes aren't included in the json string?

7
  • 1
    Your Json String is invalid, test it here : jsonlint.com Commented Apr 12, 2016 at 19:59
  • how so? and apparently this comment needs 15 characters in order to add it Commented Apr 12, 2016 at 20:01
  • or rather, how would I make it valid? Clearly the issue is in not having the quotes. Would I have to do some nasty splits? Commented Apr 12, 2016 at 20:04
  • 2
    Just to be clear: that is not Json, just Json-like. I dont think jackson can handle unquoted sring values, only unquoted keys are supported. This answer might help you: stackoverflow.com/a/34794445/5108418 Commented Apr 12, 2016 at 20:05
  • 1
    You might look into the GSON library rather than Jackson. See stackoverflow.com/questions/20557131/gson-parse-unquoted-value Commented Apr 12, 2016 at 20:10

6 Answers 6

4

SINCE GSON v2.8.6

ObjectMapper with jackson fasterxml doesn't support values without quotes, but GSON does:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonParser;

.

  JsonNode json = json("{"
      + "  name: Bob,      "
      + "  state: Colorado,"
      + "  Friends: [      "
      + "    {"
      + "      name: Dan,  "
      + "      age: 23     "
      + "    },"
      + "    {"
      + "      name: Zane, "
      + "      age: 24     "
      + "     }"
      + "  ],"
      + "  extra: \"text with spaces or colon(:) must be quoted\""
      + "}");

  Map m = new ObjectMapper().convertValue(json, Map.class);

.

JsonNode json(String content) throws IOException {

  String canonicalFormat = JsonParser.parseString(content).toString();
  return json.readTree(canonicalFormat);
}

EARLIER GSON

Before v2.8.6 GSON didn't have the static parseString method. So you should use the (deprecated in higher versions) instance method:

JsonNode json(String content) throws IOException {

  String canonicalFormat = new JsonParser().parse(content).toString();
  return json.readTree(canonicalFormat);
}

SINCE Java 15

NOTE: we expect Java 15 will support unescaped double-quotes as is:

var json = """
        {"name": "Bob", "state": "Colorado", "Friends": [{ "name": "Dan", "age": 23 }, {"name": "Zane", "age": 24 }]} """;

more details

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

Comments

2

To answer your question: There is no safe way of getting your JSON - which is not JSON by the way, because it's invalid - converted into a Map<String, Object>.

Let me elaborate just a little bit (why can't it be parsed safely?): Imagine a "JSON" like this:

{
    this is my key: and here's my value and it even has a colon:
}

Valid JSON would look something like this

{
    "this is my key": "and here's my value and it even has a colon:"
}

With the quotes a parser can safely determine keys and values. Without them a parser is lost.

2 Comments

we all know it is not valid but nevertheless we are asking because the telemetry messages we are receiving come without quotes.
@mrki102, then I suggest that you implement a "filter" which corrects the incoming data. Then you can choose any parser you like. The filter could use a little help by defining some sort of schema to let it know which field values are strings, which need quotation in addition to field keys/labels.
1

The ObjectMapper won't be able to parse the Json input if it's not valid, so the answer is no.

Test your Json here : http://jsonlint.com/

After correcting the Json input you could do :

    ObjectMapper ob = new ObjectMapper();
    ob.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
    String json = "{name: \"Bob\", state: \"Colorado\", Friends: [{ name: \"Dan\", age: 23 }, {name: \"Zane\", age: 24 }]}";

    Map<String, ObjectNode> theMap = ob.readValue(json, Map.class);
    System.out.println(theMap.get("name"));

Will print :

Bob

5 Comments

Jackson can parse invalid JSON. Notice the JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES. It just can't parse unquoted field values (it seems).
Also, your theMap will not have only String values. There are arrays in that JSON. What you've proposed is not type safe. Use an ObjectNode instead.
That's not what I meant. Not all the values are ObjectNode either. I meant more of ObjectNode root = ob.readValue(json, ObjectNode.class);
Well he asked how to convert a Json String into a Map
He also asked to do it with unquoted values. You corrected that part. You should correct the rest as well. There's no way to have a type safe parameterized Map reference here. You could have a Map<String, ?>> or Map<String, Object> but that's pretty useless. ObjectNode gives you much more flexibility.
1

you may could use the following code to preprocess the json string and then parse it.

String str = ("{requestid:\"55275645.f213506045\",timestamp:\"213506045\",bidnumber:\"55275645\",checkcode:\"1f6ad033de64d1c6357af34d4a38e9e3\",version:\"1.0\",request:{token:ee4e90c2-7a8b-4c73-bd48-1bda7e6734d5,referenceId:0.5878463922999799}}");
    str = (str.replaceAll(":\"?([^{|^]*?)\"?(?=[,|}|\\]])",":\"$1\"").replaceAll("\"?(\\w+)\"?(?=:)","\"$1\""));
    JSONObject obj = JSON.parseObject(str);
    System.out.println(obj.getJSONObject("request").getString("token"));

Comments

0

We can convert such a json to a Map using Apache Commons and Guava base libraries. Example: Input - {name=jack, id=4} Output - Map(name = jack, id = 4)

import com.google.common.base.Splitter;
import org.apache.commons.lang.StringUtils;

String input = StringUtils.substringBetween(value, "{", "}");
Map<String, String> map = 
Splitter.on(",").withKeyValueSeparator("=").split(input);

Comments

0
ObjectMapper om=new ObjectMapper();
om.configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

List<RootMember> outputList;
try {
    ObjectMapper mapper = new ObjectMapper();
    String json = mapper.writeValueAsString(resp); 
    outputList = om.readValue(json, new TypeReference<List<RootMember>>(){});
} catch (JsonMappingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (JsonProcessingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

Comments

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.