SerDe using Apache AVRO in JAVA [duplicate] - java

This question already has answers here:
How do I print my Java object without getting "SomeType#2f92e0f4"?
(13 answers)
Closed 1 year ago.
I am trying to serialize and deserialize a list of JSON objects
Below is my JSON file
[
{
"id": "01",
"Status": "Open",
"siteId": "01",
"siteName": "M1"
},
{
"id": "02",
"Status": "Open",
"siteId": "02",
"siteName": "M2"
},
{
"id": "03",
"Status": "Open",
"siteId": "03",
"siteName": "M3"
}
]
code :
public static void main(String args[]) throws IOException {
//creating schema
Schema schema = ReflectData.get().getSchema(document.class);
System.out.println("schema created: "+ schema.toString());
//get JSON list
List<document> list = getJsonList();
File fileR = new File("<<path>>/jsonlist.avro");
//Serialize objects to file
DatumWriter<document> writerR = new ReflectDatumWriter(document.class); // Serialize objects to in-memory binary data
DataFileWriter<document> outR = new DataFileWriter(writerR).create(schema, fileR); // Write binary data to file
for(int i = 0 ;i<list.size();i++)
{
outR.append((document) list.get(i));
}
outR.close();
System.out.println("Serialize objects to file...\n");
//Deserialize objects from file
DatumReader<document> readerR = new ReflectDatumReader(document.class);
DataFileReader<document> inR = new DataFileReader(fileR, readerR);
System.out.println("Deserialize objects from file...");
for(document doc : inR) {
System.out.println(doc.toString());
}
inR.close();
}
private static List<document> getJsonList() throws IOException {
final ObjectMapper objectMapper = new ObjectMapper();
String fileName = "jsonList.json";
ClassLoader classLoader = <<className>>.class.getClassLoader();
File file = new File(classLoader.getResource(fileName).getFile());
System.out.println("File Found : " + file.exists());
//list of json objects
List<document> list = objectMapper.readValue(file,new TypeReference<List<document>>(){});
returnlist;
}
When I am trying to run the above code the file is getting serialized to check the deseralization
the output is coming as
document#3246fb96
document#2e222612
I am not sure if the code for serialization is correct or where I am going wrong in the deserialization code
Referred :
https://liyanxu.blog/2018/02/07/apache-avro-examples/
Please suggest!!

Your code actually works, what you missed is to add a toString() method to your Document class.
Add something like this:
#Override
public String toString() {
return String.format("Document ID: {%s}, status: {%s}, site ID: {%s}, site name: {%s}", id, Status, siteId, siteName);
}
to the document class (which should really be Document with capital letter).
And it will print out what you want, for example something like this given the example:
Deserialize objects from file...
Document ID: {01}, status: {Open}, site ID: {01}, site name: {M1}
Document ID: {02}, status: {Open}, site ID: {02}, site name: {M2}
Document ID: {03}, status: {Open}, site ID: {03}, site name: {M3}
Alternatively, you could use the Lombok annotation #ToString. You can look into it here if you are interested.

Related

Parsing nested JSON in Java

I have a weird JSON which looks like this
[
[
{
"id": "1",
"clientId": "user"
},
{
"id": "2",
"clientId": "user"
}
],
[
{
"Status": "NotCompleted",
"StatusId": 0
},
{
"Status": "Importing",
"StatusId": 10
}
]
]
I am trying to parse it with Gson or JsonParser.
Classes look like this
public class Event {
public String id;
public String clientId;
}
public class Status {
public String Status;
public String StatusId;
}
public class AllEvents {
public Event[] events;
public Status[] statuses;
}
But when I am trying to parse it with Gson (e.g)
AllEvents[] r = new Gson().fromJson(response, AllEvents[].class);
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 6 path $[0]
Could you please help me out with parsing this kind of model? Cannot find what I am doing wrong in this case.
Thanks in advance
To solve such a problem there is two approaches:
First Approach:
Change your JSON file content(allEvents) to :
[
{
"events": [
{
"id": "1",
"clientId": "user"
},
{
"id": "2",
"clientId": "user"
}
],
"statuses": [
{
"Status": "NotCompleted",
"StatusId": 0
},
{
"Status": "Importing",
"StatusId": 10
}
]
}
]
and after that, your code will work perfectly.
Second Approach:
you need to code according to match above JSON structure:
Please find below the code which will help you.
Gson gson = new Gson();
Object[] r = gson.fromJson(loadDataAsString(), Object[].class);
AllEvents allEvents = new AllEvents();
//if your json structure position is fixed the do this commented code
//allEvents.events = gson.fromJson(gson.toJson(r[0]), Event[].class); //if your json Event structure position is fixed at 0 index
//allEvents.statuses = gson.fromJson(gson.toJson(r[1]), Status[].class); //if your json Status structure position is fixed at 1 index
//if your json structure position is not fixed the do below code
allEvents.events = Arrays.stream(r)
.flatMap(x -> Arrays.stream(gson.fromJson(gson.toJson(x), Event[].class)))
.filter(y -> y.id != null).toArray(Event[]::new);//id as primary key
allEvents.statuses = Arrays.stream(r)
.flatMap(x -> Arrays.stream(gson.fromJson(gson.toJson(x), Status[].class)))
.filter(y -> y.Status != null).toArray(Status[]::new);//Status as primary key
System.out.println(gson.toJson(allEvents));//{"events":[{"id":"1","clientId":"user"},{"id":"2","clientId":"user"}],"statuses":[{"Status":"NotCompleted","StatusId":"0.0"},{"Status":"Importing","StatusId":"10.0"}]}
Use JsonReader instead. So if you know you json starts with [ and ends with ] use read with beginArray. Your in is an InputStream, it can be a file, socket stream or string stream.
JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
List<YourMessage> messages = new ArrayList<YourMessage>();
reader.beginArray();
while (reader.hasNext()) {
messages.add (do something with reader);//<-- that is pseudo code
}
reader.endArray();
return messages;
For more detail check this link https://www.javadoc.io/doc/com.google.code.gson/gson/2.8.0/com/google/gson/stream/JsonReader.html
Solved issue in this way:
org.json.JSONArray allEvents = new org.json.JSONArray(response.getBodyAsString());
As a result I received JSONArray with 2 elements. Then extracted needed one through
allEvents.getJSONArray(0)
And then mapped in previous way with jackson ObjectMapper.
Thx for replies!

update document in couchbase server 5.1.1

I'm trying to update an object in couchbase server 5.1.1 .
additionalCodes is a list of object
Code(String code,String type,LocalDateTime datetime )
my object in couchbase is like this :
{
"code": "code1";
"creationDateTime": 1534852560000,
"additionalCodes": [
{
"code": "code1",
"type": "type1",
"dateTime": 1534772384000
}
]
}
and i do want to update this object like :
{
"code": "code1";
"creationDateTime": 1534852560000,
"additionalCodes": [
{
"code": "code1",
"type": "type1",
"dateTime": 1534772384000
},
{
"code": "code2",
"type": "type2",
"dateTime": 1534772384000
}
]
}
i'm trying this :
JsonDocument doc = bucket.get("ID");
doc.content().put("additionalCodes",new Code(...));
doc = bucket.upsert(doc);
thanks in advance
There's a few ways of doing this. You can manually convert your object graph into corresponding Json* classes:
// Code code = new Code(...);
JsonDocument doc = bucket.get("ID");
JsonArray curAddlCodes = doc.content().getArray("additionalCodes");
JsonObject newCode = JsonObject.create()
.put("code", code.code)
.put("type", code.type)
.put("dateTime", code.dateTime.toEpochSecond());
curAddlCodes.add(newCode);
doc = bucket.replace(doc);
Or you can use the subdoc API to efficiently update just the additionalCodes field, without having to fetch and send the full document:
bucket.mutateIn("ID")
.arrayAppend("additionalCodes", newCode)
.execute();
If you have a full object graph such as:
TopLevelCode(String code, LocalDateTime creationDateTime, List<Code> additionalCodes)
then you have a couple more options. You can manipulate the POJOs are you wish, then serialize it to a JSON string using a library like Jackson, and store it in a RawJsonDocument:
// TopLevelCode tlc = new TopLevelCode(...)
ObjectMapper objectMapper = com.couchbase.client.java.transcoder.JacksonTransformers.MAPPER;
String json = objectMapper.writeValueAsString(tlc);
RawJsonDocument doc = RawJsonDocument.create("ID", json);
bucket.replace(doc);
Or, if your object graph is Serializable, you could use SerializableDocument:
SerializableDocument doc = SerializableDocument.create("ID", tlc);
bucket.replace(doc);

JAXB: Unmarshal heterogeneous array

I'm trying to unmarshal using MOXy a json with the following structure:
[
{
"page": 1,
"pages": 1
},
[
{
"indicator": {
"id": "IC.BUS.EASE.XQ",
"value": "Ease of doing business index"
},
"country": {
"id": "1A",
"value": "Arab World"
},
"value": "113.952380952381",
"date": "2014"
},
...
]
]
The first element of the array is an object and the second element is another array of complex elements. I've really searched here at SO and the MOXy documentation for a simmilar example without any success.
My best attempt at mapping the json document to JAVA classes is as follows. The root class is CountryDataResponse (getters & setters ommited):
#XmlRootElement
#XmlType(propOrder ={"paginationInfo", "dataArray"})
public class CountryDataResponse {
private DataArray dataArray;
private PaginationInfo paginationInfo;
}
(I can see this is going to fail, because it isn't an array, but I'm completly lost.)
PaginationInfo class models the first element of the root array and DataArray class wraps the second element, which is an Array of Data class elements. Additionally, I've created the Indicator and Country classes for the complex types inside each Data element.
The main classes (Indicator and Country ommited):
#XmlRootElement(name = "paginationInfo")
#XmlAccessorType(XmlAccessType.FIELD)
public class PaginationInfo {
private int page;
private int pages;
}
#XmlRootElement( name = "dataArray" )
public class DataArray {
List<Data> datas;
}
#XmlRootElement(name="data")
#XmlAccessorType(XmlAccessType.FIELD)
public class Data {
private Indicator indicator;
private Country country;
private String date;
private double value;
}
Now, debugging the following code:
public static void main(String args[]) {
String test = "[{\"page\": 1,\"pages\": 1,\"per_page\": \"1000\",\"total\": 248},"
+ "["
+ "{\"indicator\": {\"id\": \"NY.GDP.MKTP.CD\",\"value\": \"GDP (current US$)\"},"
+ "\"country\": {\"id\": \"1A\",\"value\": \"Arab World\"},"
+ "\"value\": \"2853079422103.94\","
+ "\"decimal\": \"1\","
+ "\"date\": \"2013\"},"
+ "{\"indicator\": {\"id\": \"NY.GDP.MKTP.CD\",\"value\": \"GDP (current US$)\"},"
+ "\"country\": {\"id\": \"S3\",\"value\": \"Caribbean small states\"},"
+ "\"value\": \"67033118185.1864\","
+ "\"decimal\": \"1\","
+ "\"date\": \"2013\"}"
+ "]]";
JAXBContext jc = JAXBContext.newInstance(CountryDataResponse.class, Country.class, Data.class, DataArray.class, Indicator.class, PaginationInfo.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
Object res = unmarshaller.unmarshal(json, CountryDataResponse.class);
}
The res object (of class JAXBElement) has a value of type ArrayList. The first element of the array is an object of class CountryDataResponse (it should be PaginationInfo), the second is another ArrayList with elements of class CountryDataResponse, too (they should be Data instances).
Can anyone help me, please, or it is simply a malformed json and it can't be automatically unmarshalled correctly?
Thank you in advance.
Although the JSON is valid I would suggest changing the structure, something along the lines of:
{
"paginationInfo": {
"page": 1,
"pages": 1
},
"dataArray": [
{
"indicator": {
"id": "IC.BUS.EASE.XQ",
"value": "Ease of doing business index"
},
"country": {
"id": "1A",
"value": "Arab World"
},
"value": "113.952380952381",
"date": "2014"
}
]
}
This will allow you to extract the data you wish using the 'key' name which is how JSON is intended to be used.
Another approach would be to embed the data array within the paged object:
{
"page": 1,
"pages": 1,
"dataArray": [
{
"indicator": {
"id": "IC.BUS.EASE.XQ",
"value": "Ease of doing business index"
},
"country": {
"id": "1A",
"value": "Arab World"
},
"value": "113.952380952381",
"date": "2014"
}
]
}
This approach would allow you to create a generic page wrapper which could come in useful if you have multiple formats you would like to page.
Hope this helps.
Thanks to a MOXy's feature added in version 2.6, it's possible to unmarshal from javax.json.JsonStructure, javax.json.JsonObject and javax.json.JsonArray.
Using this feature I've managed to unmarshal the different parts of the original JSON to two objects: a PaginationInfo instance and an ArrayList of Data. These objects can then be used to configure an instance of CountryDataResponse, although it wouldn't be necessary as this class was created only to try to unmarshal directly from the JSON, in the first place.
public static CountryDataResponse javaSevenMode(String jsonString)
throws PropertyException, JAXBException {
Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
StringReader sr = new StringReader(jsonString);
JsonReader jsonReader = Json.createReader(sr);
JsonArray rootArray = jsonReader.readArray();
JsonObject paginationInfoJO = rootArray.getJsonObject(0);
JsonStructureSource paginationInfoJSS = new JsonStructureSource(paginationInfoJO);
PaginationInfo pi = unmarshaller.unmarshal(paginationInfoJSS, PaginationInfo.class).getValue();
JsonArray dataJArray = rootArray.getJsonArray(1);
JsonStructureSource dataArrayJSS = new JsonStructureSource(dataJArray);
List<Data> datas
= (List<Data>) unmarshaller.unmarshal(dataArrayJSS, Data.class)
.getValue();
DataArray da = new DataArray();
da.setDatas(datas);
CountryDataResponse cdr = new CountryDataResponse();
cdr.setDataArray(da);
cdr.setPaginationInfo(pi);
return cdr;
}
Thanks to #blaise-doughan for inspiration (see http://blog.bdoughan.com/2013/07/eclipselink-moxy-and-java-api-for-json.html)

Reading value of nested key in JSON with Java (Jackson)

I'm a new Java programmer coming from a background in Python. I have weather data that's being collected/returned as a JSON with nested keys in it, and I don't understand how pull the values out in this situation. I'm sure this question has been asked before, but I swear I've Googled a great deal and I can't seem to find an answer. Right now I'm using json-simple, but I tried switching to Jackson and still couldn't figure out how to do this. Since Jackson/Gson seem to be the most used libraries, I'd would love to see an example using one of those libraries. Below is a sample of the data, followed by the code I've written so far.
{
"response": {
"features": {
"history": 1
}
},
"history": {
"date": {
"pretty": "April 13, 2010",
"year": "2010",
"mon": "04",
"mday": "13",
"hour": "12",
"min": "00",
"tzname": "America/Los_Angeles"
},
...
}
}
Main function
public class Tester {
public static void main(String args[]) throws MalformedURLException, IOException, ParseException {
WundergroundAPI wu = new WundergroundAPI("*******60fedd095");
JSONObject json = wu.historical("San_Francisco", "CA", "20100413");
System.out.println(json.toString());
System.out.println();
//This only returns 1 level. Further .get() calls throw an exception
System.out.println(json.get("history"));
}
}
The function 'historical' calls another function that returns a JSONObject
public static JSONObject readJsonFromUrl(URL url) throws MalformedURLException, IOException, ParseException {
InputStream inputStream = url.openStream();
try {
JSONParser parser = new JSONParser();
BufferedReader buffReader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
String jsonText = readAll(buffReader);
JSONObject json = (JSONObject) parser.parse(jsonText);
return json;
} finally {
inputStream.close();
}
}
With Jackson's tree model (JsonNode), you have both "literal" accessor methods ('get'), which returns null for missing value, and "safe" accessors ('path'), which allow you to traverse "missing" nodes. So, for example:
JsonNode root = mapper.readTree(inputSource);
int h = root.path("response").path("history").getValueAsInt();
which would return the value at given path, or, if path is missing, 0 (default value)
But more conveniently, you can just use JSON pointer expression:
int h = root.at("/response/history").getValueAsInt();
There are other ways too, and often it is more convenient to actually model your structure as Plain Old Java Object (POJO).
Your content could fit something like:
public class Wrapper {
public Response response;
}
public class Response {
public Map<String,Integer> features; // or maybe Map<String,Object>
public List<HistoryItem> history;
}
public class HistoryItem {
public MyDate date; // or just Map<String,String>
// ... and so forth
}
and if so, you would traverse resulting objects just like any Java objects.
Use Jsonpath
Integer h = JsonPath.parse(json).read("$.response.repository.history", Integer.class);
Check out Jackson's ObjectMapper. You can create a class to model your JSON then use ObjectMapper's readValue method to 'deserialize' your JSON String into an instance of your model class. And vice-versa.
Try jpath API. It's xpath equivalent for JSON Data. You can read data by providing the jpath which will traverse the JSON data and return the requested value.
This Java class is the implementation as well as it has example codes on how to call the APIs.
https://github.com/satyapaul/jpath/blob/master/JSONDataReader.java
Readme -
https://github.com/satyapaul/jpath/blob/master/README.md
Example:
JSON Data:
{
"data": [{
"id": "13652355666_10154605514815667",
"uid": "442637379090660",
"userName": "fanffair",
"userFullName": "fanffair",
"userAction": "recommends",
"pageid": "usatoday",
"fanPageName": "USA TODAY",
"description": "A missing Indonesian man was found inside a massive python on the island of Sulawesi, according to local authorities and news reports. ",
"catid": "NewsAndMedia",
"type": "link",
"name": "Indonesian man swallowed whole by python",
"picture": "https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQBQf3loH5-XP6hH&w=130&h=130&url=https%3A%2F%2Fwww.gannett-cdn.com%2F-mm-%2F1bb682d12cfc4d1c1423ac6202f4a4e2205298e7%2Fc%3D0-5-1821-1034%26r%3Dx633%26c%3D1200x630%2Flocal%2F-%2Fmedia%2F2017%2F03%2F29%2FUSATODAY%2FUSATODAY%2F636263764866290525-Screen-Shot-2017-03-29-at-9.27.47-AM.jpg&cfs=1&_nc_hash=AQDssV84Gt83dH2A",
"full_picture": "https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQBQf3loH5-XP6hH&w=130&h=130&url=https%3A%2F%2Fwww.gannett-cdn.com%2F-mm-%2F1bb682d12cfc4d1c1423ac6202f4a4e2205298e7%2Fc%3D0-5-1821-1034%26r%3Dx633%26c%3D1200x630%2Flocal%2F-%2Fmedia%2F2017%2F03%2F29%2FUSATODAY%2FUSATODAY%2F636263764866290525-Screen-Shot-2017-03-29-at-9.27.47-AM.jpg&cfs=1&_nc_hash=AQDssV84Gt83dH2A",
"message": "Akbar Salubiro was reported missing after he failed to return from harvesting palm oil.",
"link": "http:\/\/www.usatoday.com\/story\/news\/nation-now\/2017\/03\/29\/missing-indonesian-man-swallowed-whole-reticulated-python\/99771300\/",
"source": "",
"likes": {
"summary": {
"total_count": "500"
}
},
"comments": {
"summary": {
"total_count": "61"
}
},
"shares": {
"count": "4"
}
}]
}
Code snippet:
String jPath = "/data[Array][1]/likes[Object]/summary[Object]/total_count[String]";
String value = JSONDataReader.getStringValue(jPath, jsonData);

Creating JSON in required format - Java

I am not very experienced in this so need help.I need following things to be done :
1. Want to traverse a folder structure in a content management repository.
2. Want to create JSON Object of the folder in child-node form.
3. Json data will be used to create tree using jQuery
Json format:
var data = [
{
text: "Parent 1",
nodes: [
{
text: "Child 1",
nodes: [
{
text: "Grandchild 1"
},
{
text: "Grandchild 2"
}
]
},
{
text: "Child 2"
}
]
},
{
text: "Parent 2"
},
{
text: "Parent 3"
},
{
text: "Parent 4"
},
{
text: "Parent 5"
}
];
My Java method is like this:
public static void displayIt(File node){
System.out.println(node.getAbsoluteFile());
if(node.isDirectory()){
String[] subNote = node.list();
for(String filename : subNote){
displayIt(new File(node, filename));
}
}
}
I am Struggling to frame strategy to create JSON object and Array to depict this.
Please can you help me.
If you want to read all files or folder from content management repository using recursion than use below function :
public static MyFolder readFiles(File file,List<MyFolder> myfolder,MyFolder childObj)
{
try
{
List<MyFolder> childArray = new ArrayList<MyFolder>();
if(file.isDirectory())
{
File[] file_array = file.listFiles();
if(file_array.length == 0 ){
childObj.text = file.getAbsolutePath();
myfolder.add(childObj);
childObj = new MyFolder();
}else{
childObj.text = file.getAbsolutePath();
childArray = childObj.nodes;
if(childArray == null)
childArray = new ArrayList<MyFolder>();
}
for(File tempFile : file_array)
{
if(tempFile.isDirectory())
{
childObj = readFiles(tempFile,myfolder,childObj);
if(childObj.text != null)
myfolder.add(childObj);
childObj = new MyFolder();
}
else
{
MyFolder obj = new MyFolder();
obj.text = tempFile.getAbsolutePath();
childArray.add(obj);
}
}
childObj.nodes = childArray;
}
else
{
childObj.text = file.getAbsolutePath();
myfolder.add(childObj);
childObj = new MyFolder();
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
return childObj;
}
MyFolder Class :
class MyFolder
{
String text;
List<MyFolder> nodes;
}
You need some JSON utility or API to convert your class into json string. I have used GSON google API to convert my List<MyFolder> to JSON string.
Below is my test Class to test above :
List<MyFolder> myFolder = new ArrayList<MyFolder>();
File file = new File("D:/test");
MyFolder childArray = new MyFolder();
readFiles(file,myFolder,childArray);
Gson json = new Gson();
System.out.println(json.toJson(myFolder));
Output is :
[
{
"text": "D:\\test\\test1\\test12",
"nodes": [
{
"text": "D:\\test\\test1\\test12\\test12.txt"
},
{
"text": "D:\\test\\test1\\test12\\test12_2.txt"
}
]
},
{
"text": "D:\\test\\test2"
},
{
"text": "D:\\test\\test3"
}
]
Last thing remaining is just passed this to client side and process JSON to generate tree stucture.
May this will help you.
There's a way in JAVA to produce a JSON object from different collection types - Flexjson. Here you can find most essential information about Flexjson. In short, the command looks like this:
String jsonString = new flexjson.JSONSerializer().deepSerialize(myCollection);
Jquery perfectly understands the resulting JSON object and you can easily access the contents in JQuery like this:
jsonString["column1"]
So, you can just save data in an Arra/Map/whatewer is suitable for your situation and then translate in to JSON.
Hope it helps, I use this method every time I need a JSON string and works perfectly for me.

Categories

Resources