Convert HOCON string into Java object - java

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.

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.

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.

In my opinion, we split the parse process in two step.
Format the output data to JSON.
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);
}
}

Related

Inserting String variable into JSON which is in a form of String

I have a JSON payload saved as a String
String jsonBody = “{\n”
+ ” \“example\“: {\n”
+ ” \“example\“: [\n”
+ ” {\n”
+ ” \“example\“: 100,\n”
+ ” \“this_is_example_json_key\“: \“this_is_example_json_value\“,\n”
I created that by copying body from i.e Postman into
String jsonBody = "here I pasted the body";
Unfortunately I cannot have everything hardcoded there, so I have to change some values to variables. The JSON in postman looks like:
"this_is_example_json_key":"x"
And so on. Let's assume that:
String x = “this_is_example_json_value“;
If I just replace it like
+ ” \“this_is_example_json_key\“: \“ + x + \“,\n”
or something like that, the value in the body will be just this_is_example_json_value, where I need "this_is_example_json_value" (the "" marks are part of the value).
So the question is, how to set up those + / " in the String, so in the end in the value of the JSON I will end up with the value inside " ".
I've tried to play with the " / + but nothing of those were working. Variable must be passed with those " " because otherwise, the API is sending back an error.
Since java 15, if you want only use the string, you can also do in this way:
int this_is_example_json_value= 100;
String json = """
{
"this_is_example_json_key": %d
}
""".formatted(this_is_example_json_value);
Here the official jep.
Don't try to build up JSON using strings. Use a proper JSON parser.
import org.json.JSONException;
import org.json.JSONObject;
public class Eg {
public static void main(String[] args) throws JSONException {
String x = "this_is_example_json_value";
JSONObject example = new JSONObject();
example.put("this_is_example_json_key", x);
System.out.println(example.toString());
}
}
Which outputs:
{"this_is_example_json_key":"this_is_example_json_value"}
With no messing around wondering what needs to be escaped.
you can use an extra " \ " "
String x = "this_is_example_json_value";
String jsonBody = "{\n"
+ "\"example\": {\n"
+ " \"example\": [\n"
+ " {\n"
+ " \"example\": 100,\n"
+ "\"this_is_example_json_key\":" + "\"" + x + "\"" + "\n }"
+"\n ]\n }\n }";
in this case you will get a json string
{
"example": {
"example": [
{
"example": 100,
"this_is_example_json_key": "this_is_example_json_value"
}
]
}
}

Using JSONAssert to check if an item exists in a JSON array

I have a JSONObject that is similar to something like this:
{
"category":"abc"
"staus":""open"
"external":[
{"name":"123", "type":"OTHER"},
{"name":"678", "type":"ALPHA"},
{"name":"890", "type":"DELTA"}
]
}
If I want to use JSONAssert to check if the item {"name":"678"} exists and I don't know the item's order and the number of items in the "external" array, how should I do in Java?
It seems the ArrayValueMatcher should be the way to go but I just cannot get it works.
Please help
You could use JsonPath for this usecase :
JSONArray array = JsonPath.read(json, "$.external[?(#.name == '678')]");
Assertions.assertThat(array).hasSize(1);
Here is a complete example using JsonAssert:
#Test
public void foo() throws Exception {
String jsonString = "{\n" +
" \"category\":\"abc\",\n" +
" \"staus\":\"open\",\n" +
" \"external\":[\n" +
" {\"name\":\"123\", \"type\":\"OTHER\"},\n" +
" {\"name\":\"678\", \"type\":\"ALPHA\"},\n" +
" {\"name\":\"890\", \"type\":\"DELTA\"}\n" +
" ]\n" +
"}";
JsonAssert.with(jsonString).assertThat("$.external[*].name", hasItem(equalTo("678")));
}

Splitting array in string does not give last element

Hi I am splitting and storing string with use of array but does not give result
String str = "123456";
String[] arrOfStr = str.split("");
String otpnum1 = arrOfStr[0];
String otpnum2 = arrOfStr[1];
String otpnum3 = arrOfStr[2];
String otpnum4 = arrOfStr[3];
String otpnum5 = arrOfStr[4];
String otpnum6 = arrOfStr[5];
System.out.println("otp"+otpnum1+otpnum2+otpnum3+otpnum4+otpnum5+otpnum6);
OUTPUT
System.out: otp12345
You are printing without any space or newline, which is the reason you are not able to interpret individual variables. Use this
System.out.println("otp " + otpnum1+ " " + otpnum2+" " + " "+ otpnum3+ " " + otpnum4+ " " + otpnum5+ " " + otpnum6);
I understand, the output is 12345, and expected 123456 for the result.
But, looking your code looks like correct.
I have try your code here, for test, and works fine.
The output was: otp123456

How to remove commas at the end of any string

I have Strings "a,b,c,d,,,,, ", ",,,,a,,,,"
I want these strings to be converted into "a,b,c,d" and ",,,,a" respectively.
I am writing a regular expression for this. My java code looks like this
public class TestRegx{
public static void main(String[] arg){
String text = ",,,a,,,";
System.out.println("Before " +text);
text = text.replaceAll("[^a-zA-Z0-9]","");
System.out.println("After " +text);
}}
But this is removing all the commas here.
How can write this to achieve as given above?
Use :
text.replaceAll(",*$", "")
As mentioned by #Jonny in comments, can also use:-
text.replaceAll(",+$", "")
Your first example had a space at the end, so it needs to match [, ]. When using the same regular expression multiple times, it's better to compile it up front, and it only needs to replace once, and only if at least one character will be removed (+).
Simple version:
text = text.replaceFirst("[, ]+$", "");
Full code to test both inputs:
String[] texts = { "a,b,c,d,,,,, ", ",,,,a,,,," };
Pattern p = Pattern.compile("[, ]+$");
for (String text : texts) {
String text2 = p.matcher(text).replaceFirst("");
System.out.println("Before \"" + text + "\"");
System.out.println("After \"" + text2 + "\"");
}
Output
Before "a,b,c,d,,,,, "
After "a,b,c,d"
Before ",,,,a,,,,"
After ",,,,a"

trim all String values in JsonNode

i need to trim all the String values
{
"startDate": "2015-06-29",
"endDate": "2015-07-04",
"category": "VIP ",
"name": " govind",
age: 10,
"place": " goa "
}
i am doing it by
JsonNode json = request().body().asJson();
CLassName cl = Json.fromJson(json , ClassName.class);
and trimming in setter of ClassName
suggest any other good approach because i know its not a good approach
If you can confirm that the JSON will not have quotes within values then for better performance I'd do the trimming on the raw text rather than the parsed version:
val text = request.body.asText
// RegEx explanation:
// space followed by asterisk means any number of spaces
// backward slash escapes the following character
val trimmed = text.map(_.replaceAll(" *\" *", "\""))
import play.api.libs.json.Json
val json = Json.parse(trimmed)
Java version:
import play.api.libs.json.*;
String text = request().body().asText();
String trimmed = text.replaceAll(" *\" *", "\"");
JsValue json = Json.parse(trimmed);
but changing the setter is not the right way to do it. As you would not be able to create the complete object again(even if it is required). Either you write a seperate Trimmer class which take this object and trim it. or some function in the same class. I would prefer a trimmer class
Try this:
public static void main(String[] args) {
String json =
"{"
+ " \"startDate\": \"2015-06-29\","
+ " \"endDate\": \"2015-07-04\","
+ " \"category\": \"VIP \","
+ " \"name\": \" govind\","
+ " age: 10,"
+ " \"place\": \" goa \""
+ "}";
Type stringStringMap = new TypeToken<Map<String, String>>(){}.getType();
Map<String, String> map = new Gson().fromJson(json, stringStringMap);
Map<String, String> trimed = map.entrySet().stream()
.map(e -> new AbstractMap.SimpleEntry<>(e.getKey().trim(), e.getValue().trim()))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
System.out.println(trimed);
// -> {endDate=2015-07-04, name=govind, place=goa, category=VIP, age=10, startDate=2015-06-29}
}

Categories