Jackson Object mapping approach with Linkedin Rest API - java

When dealing with Linkedin Rest API, a lot of the fields has format like this:
"positions":
{
"_total": 1,
"values": [{"title": "Software Developer"}]
}
instead of:
"positions":
{
[{"title": "Software Developer"}]
}
This causes a lot of trouble when I try to map the json to a Position object. I am using Java with Jackson to parse the JSON response. Is there a way to set up object mapper so that it would automatically ignore the "_total" and "values" field?

I think it is not possible to configure ObjectMapper to do this automatically.
You could try writing your own parser, something along these lines:
JsonFactory f = new JsonFactory();
JsonParser jp = f.createJsonParser(new File("positions.json"));
List<Position> positions = new LinkedList<Position>();
jp.nextToken(); // will return JsonToken.START_OBJECT (verify?)
while (jp.nextToken() != JsonToken.END_OBJECT) {
String fieldname = jp.getCurrentName();
jp.nextToken(); // move to value, or START_OBJECT/START_ARRAY
if ("positions".equals(fieldname)) { // contains an object
Position pos = new Position();
while (jp.nextToken() != JsonToken.END_OBJECT) {
String namefield = jp.getCurrentName();
jp.nextToken(); // move to value
if ("value".equals(namefield)) {
pos.setValue(jp.getText());
}
}
}
jp.close();

Obviously #kpentchev provided a viable solution to this issue, but I personally tend to avoid manual parser as much as possible. In this case, I ended up writing a sort of wrapper class to map the raw json:
public class PositionWrapper
{
private Long _total;
private List<Position> values;
//setter and getter
}
Although it's a bit redundant this way, but it avoids going with a manual wrapper. Works well for me, even for nested objects.

Related

How can I parse invalid JSON to Java Object using Pojo Class

I'm not sure what format this object is in but can I parse the following invalid JSON object to Java class Pojo? I tried doing it using Jackson but since it's invalid, I was wondering if pojo class would work?
{
name: (sindey, crosby)
game: "Hockey"
type: athlete
}
The file would have multiple objects of this format
Geesh, don't recognise this format! If you want to use Jackson you could pre-process you data to wrap the values... perhaps a regex to catpure the groups and wrap the values in quotes something like (name|type):\s(.+) => $1: "$2"
I was wondering if pojo class would work?
Sure, you could make that work with a simple parser; plenty of room for improvement, but something like this would do it:
Record record = null;
var records = new LinkedList<>();
// I'm using a reader as example, but just provide lines any way you like
while ((line = reader.readLine()) != null) {
line = line.trim();
// may need to skip empty lines if you have them in your file...
if (line.equals("{")) {
record = new Record();
records.add(record);
} else {
// may need substrings if your data contains ":"
var tokens = line.split(":");
var field = tokens[0];
var value = tokens[1];
if (field.equals("name")) {
// perhaps shuffle the format to something nicer here..
record.setName(value);
}
/// same for game and type fields...
}
}

Wrong order of data when converting a JTable to JSON [duplicate]

I've a problem trying to make my page printing out the JSONObject in the order i want. In my code, I entered this:
JSONObject myObject = new JSONObject();
myObject.put("userid", "User 1");
myObject.put("amount", "24.23");
myObject.put("success", "NO");
However, when I see the display on my page, it gives:
JSON formatted string: [{"success":"NO", "userid":"User 1", "bid":24.23}]
I need it in the order of userid, amount, then success. Already tried re-ordering in the code, but to no avail. I've also tried .append....need some help here thanks!!
You cannot and should not rely on the ordering of elements within a JSON object.
From the JSON specification at https://www.json.org/
An object is an unordered set of
name/value pairs
As a consequence,
JSON libraries are free to rearrange the order of the elements as they see fit.
This is not a bug.
I agree with the other answers. You cannot rely on the ordering of JSON elements.
However if we need to have an ordered JSON, one solution might be to prepare a LinkedHashMap object with elements and convert it to JSONObject.
#Test
def void testOrdered() {
Map obj = new LinkedHashMap()
obj.put("a", "foo1")
obj.put("b", new Integer(100))
obj.put("c", new Double(1000.21))
obj.put("d", new Boolean(true))
obj.put("e", "foo2")
obj.put("f", "foo3")
obj.put("g", "foo4")
obj.put("h", "foo5")
obj.put("x", null)
JSONObject json = (JSONObject) obj
logger.info("Ordered Json : %s", json.toString())
String expectedJsonString = """{"a":"foo1","b":100,"c":1000.21,"d":true,"e":"foo2","f":"foo3","g":"foo4","h":"foo5"}"""
assertEquals(expectedJsonString, json.toString())
JSONAssert.assertEquals(JSONSerializer.toJSON(expectedJsonString), json)
}
Normally the order is not preserved as below.
#Test
def void testUnordered() {
Map obj = new HashMap()
obj.put("a", "foo1")
obj.put("b", new Integer(100))
obj.put("c", new Double(1000.21))
obj.put("d", new Boolean(true))
obj.put("e", "foo2")
obj.put("f", "foo3")
obj.put("g", "foo4")
obj.put("h", "foo5")
obj.put("x", null)
JSONObject json = (JSONObject) obj
logger.info("Unordered Json : %s", json.toString(3, 3))
String unexpectedJsonString = """{"a":"foo1","b":100,"c":1000.21,"d":true,"e":"foo2","f":"foo3","g":"foo4","h":"foo5"}"""
// string representation of json objects are different
assertFalse(unexpectedJsonString.equals(json.toString()))
// json objects are equal
JSONAssert.assertEquals(JSONSerializer.toJSON(unexpectedJsonString), json)
}
You may check my post too: http://www.flyingtomoon.com/2011/04/preserving-order-in-json.html
u can retain the order, if u use JsonObject that belongs to com.google.gson :D
JsonObject responseObj = new JsonObject();
responseObj.addProperty("userid", "User 1");
responseObj.addProperty("amount", "24.23");
responseObj.addProperty("success", "NO");
Usage of this JsonObject doesn't even bother using Map<>
CHEERS!!!
Real answer can be found in specification, json is unordered.
However as a human reader I ordered my elements in order of importance. Not only is it a more logic way, it happened to be easier to read. Maybe the author of the specification never had to read JSON, I do.. So, Here comes a fix:
/**
* I got really tired of JSON rearranging added properties.
* Specification states:
* "An object is an unordered set of name/value pairs"
* StackOverflow states:
* As a consequence, JSON libraries are free to rearrange the order of the elements as they see fit.
* I state:
* My implementation will freely arrange added properties, IN SEQUENCE ORDER!
* Why did I do it? Cause of readability of created JSON document!
*/
private static class OrderedJSONObjectFactory {
private static Logger log = Logger.getLogger(OrderedJSONObjectFactory.class.getName());
private static boolean setupDone = false;
private static Field JSONObjectMapField = null;
private static void setupFieldAccessor() {
if( !setupDone ) {
setupDone = true;
try {
JSONObjectMapField = JSONObject.class.getDeclaredField("map");
JSONObjectMapField.setAccessible(true);
} catch (NoSuchFieldException ignored) {
log.warning("JSONObject implementation has changed, returning unmodified instance");
}
}
}
private static JSONObject create() {
setupFieldAccessor();
JSONObject result = new JSONObject();
try {
if (JSONObjectMapField != null) {
JSONObjectMapField.set(result, new LinkedHashMap<>());
}
}catch (IllegalAccessException ignored) {}
return result;
}
}
from lemiorhan example
i can solve with just change some line of lemiorhan's code
use:
JSONObject json = new JSONObject(obj);
instead of this:
JSONObject json = (JSONObject) obj
so in my test code is :
Map item_sub2 = new LinkedHashMap();
item_sub2.put("name", "flare");
item_sub2.put("val1", "val1");
item_sub2.put("val2", "val2");
item_sub2.put("size",102);
JSONArray itemarray2 = new JSONArray();
itemarray2.add(item_sub2);
itemarray2.add(item_sub2);//just for test
itemarray2.add(item_sub2);//just for test
Map item_sub1 = new LinkedHashMap();
item_sub1.put("name", "flare");
item_sub1.put("val1", "val1");
item_sub1.put("val2", "val2");
item_sub1.put("children",itemarray2);
JSONArray itemarray = new JSONArray();
itemarray.add(item_sub1);
itemarray.add(item_sub1);//just for test
itemarray.add(item_sub1);//just for test
Map item_root = new LinkedHashMap();
item_root.put("name", "flare");
item_root.put("children",itemarray);
JSONObject json = new JSONObject(item_root);
System.out.println(json.toJSONString());
JavaScript objects, and JSON, have no way to set the order for the keys. You might get it right in Java (I don't know how Java objects work, really) but if it's going to a web client or another consumer of the JSON, there is no guarantee as to the order of keys.
Download "json simple 1.1 jar" from this https://code.google.com/p/json-simple/downloads/detail?name=json_simple-1.1.jar&can=2&q=
And add the jar file to your lib folder
using JSONValue you can convert LinkedHashMap to json string
For those who're using maven, please try com.github.tsohr/json
<!-- https://mvnrepository.com/artifact/com.github.tsohr/json -->
<dependency>
<groupId>com.github.tsohr</groupId>
<artifactId>json</artifactId>
<version>0.0.1</version>
</dependency>
It's forked from JSON-java but switch its map implementation with LinkedHashMap which #lemiorhan noted above.
As all are telling you, JSON does not maintain "sequence" but array does, maybe this could convince you:
Ordered JSONObject
For Java code, Create a POJO class for your object instead of a JSONObject.
and use JSONEncapsulator for your POJO class.
that way order of elements depends on the order of getter setters in your POJO class.
for eg. POJO class will be like
Class myObj{
String userID;
String amount;
String success;
// getter setters in any order that you want
and where you need to send your json object in response
JSONContentEncapsulator<myObj> JSONObject = new JSONEncapsulator<myObj>("myObject");
JSONObject.setObject(myObj);
return Response.status(Status.OK).entity(JSONObject).build();
The response of this line will be
{myObject : {//attributes order same as getter setter order.}}
The main intention here is to send an ordered JSON object as response. We don't need javax.json.JsonObject to achieve that. We could create the ordered json as a string.
First create a LinkedHashMap with all key value pairs in required order. Then generate the json in string as shown below.
Its much easier with Java 8.
public Response getJSONResponse() {
Map<String, String> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("A", "1");
linkedHashMap.put("B", "2");
linkedHashMap.put("C", "3");
String jsonStr = linkedHashMap.entrySet().stream()
.map(x -> "\"" + x.getKey() + "\":\"" + x.getValue() + "\"")
.collect(Collectors.joining(",", "{", "}"));
return Response.ok(jsonStr).build();
}
The response return by this function would be following:
{"A":"1","B":"2","C":"3"}
Underscore-java uses linkedhashmap to store key/value for json. I am the maintainer of the project.
Map<String, Object> myObject = new LinkedHashMap<>();
myObject.put("userid", "User 1");
myObject.put("amount", "24.23");
myObject.put("success", "NO");
System.out.println(U.toJson(myObject));
I found a "neat" reflection tweak on "the interwebs" that I like to share.
(origin: https://towardsdatascience.com/create-an-ordered-jsonobject-in-java-fb9629247d76)
It is about to change underlying collection in org.json.JSONObject to an un-ordering one (LinkedHashMap) by reflection API.
I tested succesfully:
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import org.json.JSONObject;
private static void makeJSONObjLinear(JSONObject jsonObject) {
try {
Field changeMap = jsonObject.getClass().getDeclaredField("map");
changeMap.setAccessible(true);
changeMap.set(jsonObject, new LinkedHashMap<>());
changeMap.setAccessible(false);
} catch (IllegalAccessException | NoSuchFieldException e) {
e.printStackTrace();
}
}
[...]
JSONObject requestBody = new JSONObject();
makeJSONObjLinear(requestBody);
requestBody.put("username", login);
requestBody.put("password", password);
[...]
// returned '{"username": "billy_778", "password": "********"}' == unordered
// instead of '{"password": "********", "username": "billy_778"}' == ordered (by key)
Just add the order with this tag
#JsonPropertyOrder({ "property1", "property2"})
Not sure if I am late to the party but I found this nice example that overrides the JSONObject constructor and makes sure that the JSON data are output in the same way as they are added. Behind the scenes JSONObject uses the MAP and MAP does not guarantee the order hence we need to override it to make sure we are receiving our JSON as per our order.
If you add this to your JSONObject then the resulting JSON would be in the same order as you have created it.
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import org.json.JSONObject;
import lombok.extern.java.Log;
#Log
public class JSONOrder {
public static void main(String[] args) throws IOException {
JSONObject jsontest = new JSONObject();
try {
Field changeMap = jsonEvent.getClass().getDeclaredField("map");
changeMap.setAccessible(true);
changeMap.set(jsonEvent, new LinkedHashMap<>());
changeMap.setAccessible(false);
} catch (IllegalAccessException | NoSuchFieldException e) {
log.info(e.getMessage());
}
jsontest.put("one", "I should be first");
jsonEvent.put("two", "I should be second");
jsonEvent.put("third", "I should be third");
System.out.println(jsonEvent);
}
}
Just use LinkedHashMap to keep de order and transform it to json with jackson
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.LinkedHashMap;
LinkedHashMap<String, Object> obj = new LinkedHashMap<String, Object>();
stats.put("aaa", "aaa");
stats.put("bbb", "bbb");
stats.put("ccc", "ccc");
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
System.out.println(json);
maven dependency
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.10.7</version>
</dependency>
I just want the order for android unit tests that are somehow randomly changing overtime with this cool org.json.JSONObject, even thou it looks like it uses linked map but probably depends on api you compile it with or something, so it has different impl. with different android api probably.
I would suggest something like this:
object Json {
#SuppressLint("DiscouragedPrivateApi")
fun Object() = org.json.JSONObject().apply {
runCatching {
val nameValuePairs: Field = javaClass.getDeclaredField("nameValuePairs")
nameValuePairs.isAccessible = true
nameValuePairs.set(this, LinkedHashMap<String, Any?>())
}.onFailure { it.printStackTrace() }
}
}
Usage:
val jsonObject = Json.Object()
...
This is just some possibility I use it little differently so I modified it to post here. Sure gson or other lib is another option.
Suggestions that specification is bla bla are so shortsighted here, why you guys even post it, who cares about 15 years old json spec, everyone wants it ordered anyway.

How to convert from Json to Protobuf?

I'm new to using protobuf, and was wondering if there is a simple way to convert a json stream/string to a protobuf stream/string in Java?
For example,
protoString = convertToProto(jsonString)
I have a json string that I want to parse into a protobuf message. So, I want to first convert the json string to protobuf, and then call Message.parseFrom() on it.
With proto3 you can do this using JsonFormat. It parses directly from the JSON representation, so there is no need for separately calling MyMessage.parseFrom(...). Something like this should work:
JsonFormat.parser().merge(json_string, builder);
//You can use this for converting your input json to a Struct / any other Protobuf Class
import com.google.protobuf.Struct.Builder;
import com.google.protobuf.Struct;
import com.google.protobuf.util.JsonFormat;
import org.json.JSONObject;
JSONObject parameters = new JSONObject();
Builder structBuilder = Struct.newBuilder();
JsonFormat.parser().merge(parameters.toString(), structBuilder);
// Now use the structBuilder to pass below (I used it for Dialog Flow V2 Context Management)
Since someone asked about getting the exception "com.google.protobuf.InvalidProtocolBufferException: JsonObject" when following Adam's advice--I ran into the same issue. Turns out it was due to the google protobuf timestamps. They are being serialized as an object containing two fields "seconds" and "nanos", since this isn't production code, I just got around this by parsing the JSON using jackson, going through the JSON object recursively and changing every timestamp from an object to a string formatted as per RFC 3339, I then serialized it back out and used the protobuf JSON parser as Adam has shown. This fixed the issue. This is some throwaway code I wrote (in my case all timestamp fields contain the word "timestamp", this could be more robust, but I don't care):
public Map<String, Object> fixJsonTimestamps(Map<String, Object> inMap) {
Map<String, Object> outMap = new HashMap<>();
for(String key : inMap.keySet()) {
Object val = inMap.get(key);
if(val instanceof Map) {
Map<String, Object> valMap = (Map<String, Object>)val;
if(key.toLowerCase().contains("timestamp") &&
valMap.containsKey("seconds") && valMap.containsKey("nanos")) {
if(valMap.get("seconds") != null) {
ZonedDateTime d = ZonedDateTime.ofInstant(Instant.ofEpochSecond((int)valMap.get("seconds")).plusNanos((int)valMap.get("nanos")),
ZoneId.of("UTC"));
val = d.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
}
} else {
val = fixJsonTimestamps(valMap);
}
} else if(val instanceof List && ((List) val).size() > 0 &&
((List) val).get(0) instanceof Map) {
List<Map<String, Object>> outputList = new ArrayList<>();
for(Map item : (List<Map>)val) {
outputList.add(fixJsonTimestamps(item));
}
val = outputList;
}
outMap.put(key, val);
}
return outMap;
}
Not the most ideal solution but it works for what I am doing, I think I saw someone recommend using a different timestamp class.
You can convert json string to Proto using builder and json String
Example :
YourProto.Builder protoBuilder = YourProto.newBuilder();
JsonFormat.parser().merge(JsonString, protoBuilder);
If you want to ignore unknown json field then
YourProto.Builder protoBuilder = YourProto.newBuilder();
JsonFormat.parser()..ignoringUnknownFields().merge(JsonString, protoBuilder);
Another way is, to use mergeFrom method from ProtocolBuffer
Example :
YourProto.Builder protoBuilder = YourProto.newBuilder();
protoBuilder.mergeFrom(JsonString.getBytes());
Once it execute, you will get all the data in protoBuilder from json String
online service:
https://json-to-proto.github.io/
This tool instantly converts JSON into a Protobuf. Paste a JSON structure on the left and the equivalent Protobuf will be generated to the right, which you can paste into your program. The script has to make some assumptions, so double-check the output!

Extract Specific JSON Object and Display Them Independently

I have data that looks like this
{
"status": "success",
"data": {
"data1": {
"serialNumber": "abc123",
"version": "1.6"
},
"data2": {
"irrelvent": [
"irrelvent",
"irrelvent"
]
},
"data3": {
"irrelevantLibs": {
"irrelevantFiles": [
"irrelevant.jar",
"irrelevant.jar",
"irrelevant.jar"
]
}
},
"data4": {
"configuration": "auth"
}
}
}
I am using the Jackson JSON Processor. What I need to do under the data object is to extract each data(x) into it's own data.
Hard to explain but I will try to be detailed. My intent is to make the JSON data more readable for our customers. So I'm trying to make the JSON data more friendly by splitting each data(x) object into blocks/tables on a website. So data1 will be displayed independently. Then data2 will be displayed independently and so on. So in this case I have four data(x) objects and I want to store those four objects into four different Strings and display them however I want. My problem is how do I get the Jackson Processor to do this?
Not sure if this is helpful but my current JSON function to process the JSON data is this:
public static String stringify(Object o) {
try {
ObjectMapper mapper = new ObjectMapper();
DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
printer.indentArraysWith(new Lf2SpacesIndenter());
return mapper.writer(printer).writeValueAsString(o);
} catch (Exception e) {
return null;
}
}
I'm positive that I can manipulate the processor to get those data separated but I don't know where to start.
EDIT: Hmm, since Jackson seems to be a pretty difficult parser to work with, would it be easier if I used the Javascript JSON parser to extract only the data objects? Since I already have Jackson convert the JSON data into a String, using Javascript would work?
"Hmm, since Jackson seems to be a pretty difficult parser to work with, would it be easier if I used the Javascript JSON parser to extract only the data objects?"
Seeing as you are working with Java have you considered using Sling? http://sling.apache.org/ It is an external library which will allow you parser and explore JSON data structures quite swiftly, and most of all cleanly.
So I was able to figure it out after really digging into the documentation. I had to use JsonNode in order to extract what I wanted. Note that the variable appName is just there for me to easily display the string data(x) while iteNode is just all elements under data(x)
public static List<String> jsonSplit(String o) throws JsonParseException, JsonMappingException, IOException {
List<String> list = new ArrayList<String>();
ObjectMapper mapper = new ObjectMapper();
DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
printer.indentArraysWith(new Lf2SpacesIndenter());
JsonNode rootNode = mapper.readValue(o, JsonNode.class);
Iterator<String> appName = rootNode.get("data").getFieldNames();
Iterator<JsonNode> iteNode = rootNode.get("data").getElements();
while (iteNode.hasNext()){
list.add(appName.next());
list.add(mapper.writer(printer).writeValueAsString(iteNode.next()));
}
return list;
}

Getting a value from deep inside JSON

I am connecting to a third party API and getting back a long JSON string. I only need one value from it, but it is located pretty deep inside the hierarchy. Is there a simple way to get it, without going through the whole thing? I looked all over but nothing seems easy.
Here's my example:
"response":{"status":1,"httpStatus":200,"data":{"myDesiredInfo":"someInfo"},"errors":[],"errorMessage":null}}
I've been trying to use Gson so I can get this blob as a JsonObject. I was sure there's something simple, like this:
jsonObject.get("myDesiredInfo")
or at the minimum something like this:
jsonObject.get("response.data.myDesiredInfo")
But it doesn't seem to exist.
So is there any parser out there that will allow me to do this?
This is my json string
String s="{"age":0,"name":"name","email":"emailk","address":{"housename":"villa"}}";
I use following code to get housename
JsonElement je = new JsonParser().parse(s);
JsonObject asJsonObject = je.getAsJsonObject();
JsonElement get = asJsonObject.get("address");
System.out.println(s + "\n" + get);
JsonObject asJsonObject1 = get.getAsJsonObject();
JsonElement get1 = asJsonObject1.get("housename");
System.out.println(get1);
The Following is my output :
{"age":0,"name":"name","email":"emailk","address":{"housename":"villa"}}
{"housename":"villa"}
"villa"
I don't think there is another way to do this. I also tried to do in other ways but i didn't get any output.
The following way you can retrieve from your jsonObject.
JSONObject jObject = new JSONObject(yourresponse);
Log.i("Desired Info is ",jObject.getJSONObject("response").getJSONObject("data").getString("myDesiredInfo"));
I wrote a little utility method that uses Gson's API to get a value as String from a JSON object, based on a java.util.List of values. So for my original question the list objects will be "response", "data", "myDesiredInfo."
Surely this can be improved on, but it's a start.
/*
* Takes a JsonObject and parses it for a primitive value, going level by level
* according to the values in #infos
*/
public static String parseJson(JsonObject json, List<String> infos) {
try {
if(infos.size() == 0) {
return json.toString();
}
JsonElement je = json.get((String)infos.get(0));
infos.remove(0);
if(je instanceof JsonObject) {
return parseJson(je.getAsJsonObject(), infos);
} else {
return je.getAsString();
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
Most languages have a JSON decoding library, a lot of them native. No idea what language you're using so here's PHP as an example:
$jsonObj = json_decode($json);
$json->response->data->myDesiredInfo;
Ruby, Python, Java - all these languages have good libraries.

Categories

Resources