3

One of my webservice return below Java string:

[
  {
    id=5d93532e77490b00013d8862, 
    app=null,
    manufacturer=pearsonEducation, 
    bookUid=bookIsbn, 
    model=2019,
    firmware=[1.0], 
    bookName=devotional, 
    accountLinking=mandatory
  }
]

I have the equivalent Java object for the above string. I would like to typecast or convert the above java string into Java Object.

I couldn't type-cast it since it's a String, not an object. So, I was trying to convert the Java string to JSON string then I can write that string into Java object but no luck getting invalid character "=" exception.

Can you change the web service to return JSON?

That's not possible. They are not changing their contracts. It would be super easy if they returned JSON.

ETO
  • 6,970
  • 1
  • 20
  • 37
VelNaga
  • 3,593
  • 6
  • 48
  • 82
  • They are not clear with the format so we may expect comma in the string. Do we have any other way? – VelNaga Oct 08 '19 at 14:54
  • 2
    @f1sh Actually, it is a standard format. It's called [HOCON](https://github.com/lightbend/config/blob/master/HOCON.md). – ETO Oct 08 '19 at 18:11

3 Answers3

10

The format your web-service returns has it's own name HOCON. (You can read more about it here)

You do not need your custom parser. Do not try to reinvent the wheel. Use an existing one instead.


Add this maven dependency to your project:

<dependency>
    <groupId>com.typesafe</groupId>
    <artifactId>config</artifactId>
    <version>1.3.0</version>
</dependency>

Then parse the response as follows:

Config config = ConfigFactory.parseString(text);

String id = config.getString("id");
Long model = config.getLong("model");

There is also an option to parse the whole string into a POJO:

MyResponsePojo response = ConfigBeanFactory.create(config, MyResponsePojo.class);

Unfortunately this parser does not allow null values. So you'll need to handle exceptions of type com.typesafe.config.ConfigException.Null.


Another option is to convert the HOCON string into JSON:

String hoconString = "...";
String jsonString = ConfigFactory.parseString(hoconString)
                                 .root()
                                 .render(ConfigRenderOptions.concise());

Then you can use any JSON-to-POJO mapper.

ETO
  • 6,970
  • 1
  • 20
  • 37
0

Well, this is definitely not the best answer to be given here, but it is possible, at least…

Manipulate the String in small steps like this in order to get a Map<String, String> which can be processed. See this example, it's very basic:

public static void main(String[] args) {
    String data = "[\r\n" 
            + "  {\r\n"
            + "    id=5d93532e77490b00013d8862, \r\n"
            + "    app=null,\r\n"
            + "    manufacturer=pearsonEducation, \r\n"
            + "    bookUid=bookIsbn, \r\n"
            + "    model=2019,\r\n"
            + "    firmware=[1.0], \r\n"
            + "    bookName=devotional, \r\n"
            + "    accountLinking=mandatory\r\n"
            + "  }\r\n"
            + "]";

    // manipulate the String in order to have
    String[] splitData = data
            // no leading and trailing [ ] - cut the first and last char
            .substring(1, data.length() - 1)
            // no linebreaks
            .replace("\n", "")
            // no windows linebreaks
            .replace("\r", "")
            // no opening curly brackets
            .replace("{", "")
            // and no closing curly brackets.
            .replace("}", "")
            // Then split it by comma
            .split(",");

    // create a map to store the keys and values
    Map<String, String> dataMap = new HashMap<>();

    // iterate the key-value pairs connected with '='
    for (String s : splitData) {
        // split them by the equality symbol
        String[] keyVal = s.trim().split("=");
        // then take the key
        String key = keyVal[0];
        // and the value
        String val = keyVal[1];
        // and store them in the map ——> could be done directly, of course
        dataMap.put(key, val);
    }

    // print the map content
    dataMap.forEach((key, value) -> System.out.println(key + " ——> " + value));
}

Please note that I just copied your example String which may have caused the line breaks and I think it is not smart to just replace() all square brackets because the value firmware seems to include those as content.

deHaar
  • 17,687
  • 10
  • 38
  • 51
0

In my opinion, we split the parse process in two step.

  1. Format the output data to JSON.
  2. Parse text by JSON utils.

In this demo code, i choose regex as format method, and fastjson as JSON tool. you can choose jackson or gson. Furthermore, I remove the [ ], you can put it back, then parse it into array.

import com.alibaba.fastjson.JSON;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SerializedObject {
    private String id;
    private String app;

    static Pattern compile = Pattern.compile("([a-zA-Z0-9.]+)");
    public static void main(String[] args) {
        String str =
                "  {\n" +
                "    id=5d93532e77490b00013d8862, \n" +
                "    app=null,\n" +
                "    manufacturer=pearsonEducation, \n" +
                "    bookUid=bookIsbn, \n" +
                "    model=2019,\n" +
                "    firmware=[1.0], \n" +
                "    bookName=devotional, \n" +
                "    accountLinking=mandatory\n" +
                "  }\n";
        String s1 = str.replaceAll("=", ":");
        StringBuffer sb = new StringBuffer();
        Matcher matcher = compile.matcher(s1);
        while (matcher.find()) {
            matcher.appendReplacement(sb, "\"" + matcher.group(1) + "\"");
        }
        matcher.appendTail(sb);
        System.out.println(sb.toString());

        SerializedObject serializedObject = JSON.parseObject(sb.toString(), SerializedObject.class);
        System.out.println(serializedObject);
    }
}
caisil
  • 363
  • 2
  • 14