EOF Exception using Jackson - java

I am using Jackson to parse an external file which contains json. The json in the file takes this form:
{
"timestamp": MY_TIMESTAMP,
"serial": "MY_SERIAL",
"data": [{
MY_DATA
}, {
MY_DATA
}]
}
The code I am trying to use to access this is as follows:
JsonNode root = mapper.readTree(dataFileLocation);
JsonNode data = root.get("data");
ArrayList<AriaInactiveExchange> exchangeList = mapper.readValue(data.toString(), new TypeReference<List<AriaInactiveExchange>>(){});
I have validated the location of the dataFile and the data in it. I'm positive that i'm doing something wrong and that this may not even be the right approach. But the idea is clear that I need to get to "data" and map that to an Array.
When this code is run the following line instantly throws an EOF exception:
JsonNode root = mapper.readTree(dataFileLocation);

Related

Marshalling API response to List<POJO> with Jackson

I am having trouble parsing the response from an Adobe Campaign API endpoint into a POJO.
I am grabbing the data from the response:
String json = EntityUtils.toString(response.getEntity());
The data (heavily redacted) data looks like this:
{
"content": [
{
"PKey": "#9v59tLj9c.....",
"age": 36,
"birthDate": "1986-04-30",
"blackList": false,
...
},
{
"PKey": "#9f32tLj5c.....",
"age": 32,
"birthDate": "1999-05-11",
"blackList": false,
...
},
...
]
}
I'm instantiating a Jackson ObjectMapper and configuring it such that the root "content" node is ignored.
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
I have tried many different ways of parsing the data into my Profile POJO, without success. There's always an issue related to it being wrapped in "content" node, or being a list of one, or something. For brevity, the code below is for a single POJO, but I have also tried with List<Profile> since, as mentioned, the response is always a List of one or more.
// object mapper
Profile profile = objectMapper.readValue(json), Profile.class)
// ERROR: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "content" (class com.example.adobecampaignprototype.Profile), not marked as ignorable (0 known properties: ])
// object reader
ObjectReader objectReader = objectMapper.readerFor(Profile.class).withRootName("content");
Profile profile = objectReader.readValue(json);
// ERROR: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `com.example.adobecampaignprototype.Profile` from Array value (token `JsonToken.START_ARRAY`)
// array node
ArrayNode arrayNode = (ArrayNode) objectMapper.readTree(json).get("content");
// ERROR: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "content" (class com.example.adobecampaignprototype.Profile), not marked as ignorable (0 known properties: ])
// json node
JsonNode jsonNodeRoot = objectMapper.readTree(json);
JsonNode jsonNodeNested = jsonNodeRoot.get("content");
JsonNode jsonNodeActual = jsonNodeNested.get(0) // to get profile at index 0
JsonNode jsonNodeActualValue = jsonNodeActual.get("PKey") // to read single property
I've tried the above in many combinations, but have never been able to successfully parse either a Profile or List. I have read the official docs exhaustively, been through tutorials on Baeldung and elsewhere. I feel like this should be a simple thing and there's probably something obvious that I'm overlooking, but unsure what it is. Would be grateful if someone could point me toward the EASY button.
Probably you are overthinking about it, for example if you take a semplified version of your json input file like below as a starting point:
{
"content": [
{
"PKey": "#9v59tLj9c....."
},
{
"PKey": "#9f32tLj5c....."
}
]
}
You can use part of the code you wrote, so one way to deserialize it is to convert your ArrayNode array of JsonNode into a Profile[] array:
#Data
public class Profile {
#JsonProperty("PKey")
private String pKey;
}
ArrayNode arrayNode = (ArrayNode) mapper.readTree(json).get("content");
Profile[] profiles = mapper.convertValue(arrayNode, Profile[].class);
//ok it prints the array [{"PKey":"#9v59tLj9c....."},{"PKey":"#9f32tLj5c....."}]
System.out.println(mapper.writeValueAsString(profiles));

How to get Json key value for unkown json object structure

I have an array of JSON objects but its structure is unknown.i have struck
with how to get the value and based on value i need to generate code
"memberjson": [{
"company": {
"employee": {
"software": {
"employeetype": "permanent"
},
"type1": "401",
"type2": "541"
}
}
}, {
"trust": {
"people": {
"contract": {
"type": "available"
},
"type4": "4541",
"type5": "58771"
}
}
}]
}
How to get the value however I can request to give the path Example
JSON path 1: company.employee.software.employeetype
JSON path 2: trust.people.contract.type^trust.people.type4^trust.people.contract.type4
Based on the path I need to get the value.
in which format I need to store path so that I can get the value easily or please suggest me is there any other way to get the value for the unknown structure
Also, I need to generate code from above JSON:
Ex:
For JSON path 1: company.employee.software.employeetype^employee.company.type1^
^employee.company.type2
"generatedkey"=company.employee.software.employeetype+employee.company.type1+employee.company.type2
Final Ans:
"generatedkey":"permanent401541"
JSON path 2: trust.people.contract.type^trust.people.type4^trust.people.contract.type4
"generatedkey"=trust.people.contract.type+trust.people.type4+trust.people.contract.type4
Final Ans:
"generatedkey":"available454158771"
I tried to iterate based on a path
There is a library called JSON Path https://www.npmjs.com/package/jsonpath, here you write regular expression for the path to get the value
To test use this online tool called json path evaluator https://jsonpath.com/ to verify your path

java native JSON api for parsing

I've following JSON structure coming in,
{
"name": "product new",
"brand": {
"id": 1
},
"category": {
"id": 1
}
}
I can extract
jsonObject = Json.createReader(httpServletRequest.getInputStream()).readObject();
jsonObject.getString("name")
Errors:
jsonObject.getInt("brand.id")
jsonObject.getInt("category.id")
I'm using Java API for JSON.
Edit If I access
System.out.println(jsonObject.get("brand"));
// response {"id":1}
System.out.println(jsonObject.get("brand.id"));
// null
http://www.oracle.com/technetwork/articles/java/json-1973242.html
I don't think the API you're using supports nested expressions. You'll need to access the parent object, and then the specific field:
System.out.println(jsonObject.getJsonObject("brand").getInt("id"));
Or you can use an API that accepts a path expression, like Jackson:
JsonNode node = new ObjectMapper().readTree(httpServletRequest.getInputStream());
System.out.println(node.at("/brand/id").asInt());

Validating entire string as json using jackson

I'm using the following code to parse json
new com.fasterxml.jackson.databind.ObjectMapper().readTree(jsonStr)
But it parses the following string successfully since it looks like it stops processing once it finds a valid tree, even though the string in its entirety is not a valid json.
{
"name": "test",
},
"field": "c"
}
Is there a way to make it consider the entire string or stream passed? I couldn't find an appropriate option in DeserializationFeature.
Note that the solution doesn't have to involve jackson. If there's a simpler way to do that in java or scala, that'll suffice too.
With Jackson you can use Streaming API, JsonParser, to read a json like and validate like follows:
final JsonFactory jsonFactory = new JsonFactory();
jsonFactory.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
try (JsonParser parser = jsonFactory.createParser(invalidJson)) {
while (!parser.isClosed()) {
parser.nextToken();
}
}
For example, if there is json string of
{
"name": "test"
},
"field": "c"
}
A JsonParseException will be thrown as follows:
Exception in thread "main"
com.fasterxml.jackson.core.JsonParseException: Unexpected character
(',' (code 44)): expected a valid value (number, String, array,
object, 'true', 'false' or 'null') at [Source: {
"name": "test"
},
"field": "c"
}; line: 3, column: 3]
jsonFactory.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION) is to explicitly check that no duplicate JSON Object field names are encountered. If enabled, parser will check all names within context and report duplicates by throwing a JsonParseException
According to : http://jsonlint.com/
The JSON you are using is not valid. You might want to correct it to get rid of the Exception :
{
"name": "test",
"field": "c"
}

Cloudera Navigator API fail to fetch nested data

I am working in Cloudera Manager Navigator REST API where extracting result is working fine, but unable to get any nested value.
The type of data is extracting as below.
{
"parentPath": "String",
"customProperties": "Map[string,string]",
"sourceType": "String",
"entityType": "String"
}
And data should be like
{
"parentPath": "abcd",
"customProperties": {
"nameservice" : "xyz"
},
"sourceType": "rcs",
"entityType": "ufo"
}
But I am getting key-value result as follows.
parentPath :abcd
customProperties : null
sourceType : rcs
entityType : ufo
In above response data, "customProperties" is coming with a null value where it should return a map object contains ["nameservice" : "xyz"]. This is the problem with following code snippet.
MetadataResultSet metadataResultSet = extractor.extractMetadata(null, null,"sourceType:HDFS", "identity:*");
Iterator<Map<String, Object>> entitiesIt = metadataResultSet.getEntities().iterator();
while(entitiesIt.hasNext()){
Map<String, Object> result = entitiesIt.next();
for(String data : result.keySet()){
System.out.println(" key:"+data+" value:"+result.get(data));
}
}
Can you suggest me how to get the nested value where datatype is complex.
have u checked how the data looks on navigator ui? You can first verify that once, and also try cloudera /entities/entity-id rest API in browser to check how json response is coming

Categories