I have this Json content:
{
"people":[
{
"name":"test1",
"sirname":"test2",
"details":{
"social_no":1234567,
"creadit_card_no":34582342309
}
},
{
"name":"test3",
"sirname":"test4",
"details":{
"social_no":12345679,
"creadit_card_no":345823423090
}
}
]
}
and according to logic this Json should have 3 POJO classes: A class that will hold the list of People, People object and a Details object.
Now my question is, is it possible to deserialize this Json using Jackson or if not possible with Jackson, with GSON library? One that will contain the list of People, and another one, for example Human class, that will have the following structure:
public class Human{
String name;
String sirname;
String social_no;
String creadit_card_no;
//..getters and setters
//should correspond with this json fragment:
// {
// "name":"test1",
// "sirname":"test2",
// "details":{
// "social_no":1234567,
// "creadit_card_no":34582342309
// }
}
}
So if this is possible, how can I do this?
Update
My actuall json structure is different than the example given here, so here is the original json
So I've created a TypeAdapter on my own, here is the code from this class:
public class PlanTypeAdapter extends TypeAdapter<Plan> {
private final String TAG = PlanTypeAdapter.class.getSimpleName();
#Override
public void write(JsonWriter out, Plan value) throws IOException {
Log.d(TAG, "WRITE");
}
#Override
public Plan read(JsonReader reader) throws IOException {
Log.d(TAG, "READ");
Plan plan = new Plan();
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
reader.setLenient(false);
while (reader.hasNext()) {
Log.d(TAG, "PATH: " + reader.getPath());
Log.d(TAG, "PEEK: " + reader.peek());
if (reader.peek() == JsonToken.BEGIN_OBJECT) {
Log.d(TAG, "BEGIN object, path: " + reader.getPath());
reader.beginObject();
} else if (reader.peek() == JsonToken.NULL) {
Log.d(TAG, "NULL");
reader.skipValue();
} else if (reader.peek() == JsonToken.END_ARRAY) {
Log.d(TAG, "END ARRAY");
if (reader.getPath().contains("retailer")) {
reader.endObject();
} else {
reader.endArray();
}
} else if (reader.peek() == JsonToken.END_OBJECT) {
reader.endObject();
Log.d(TAG, "END object, path: " + reader.getPath());
} else if (reader.peek() == JsonToken.NUMBER) {
Log.d(TAG, "NUMBER " + reader.getPath());
} else if (reader.peek() == JsonToken.BOOLEAN) {
Log.d(TAG, "BOOLEAN " + reader.getPath());
} else if (reader.peek() == JsonToken.NAME) {
switch (reader.nextName()) {
case "retailer":
reader.beginObject();
Log.d(TAG, "RET");
break;
case "national_plan":
reader.beginObject();
Log.d(TAG, "NPlan");
break;
case "name":
if (reader.getPath().contains("retailer")) {
plan.setRetailer_name(reader.nextString());
reader.skipValue();
reader.skipValue();
reader.endObject();
} else {
reader.skipValue();
}
break;
case "contract_end":
plan.setContract_end(reader.nextString());
break;
case "data_level_gb":
plan.setData_level_gb(reader.nextString());
break;
case "data_level_id":
plan.setData_level_id(reader.nextInt());
break;
case "days_to_end":
plan.setDays_to_switch(reader.nextInt());
break;
case "direct_from_operator":
plan.setDirect_from_operator(reader.nextBoolean());
break;
case "calculation_amount":
plan.setCalculationAmount(reader.nextDouble());
break;
case "network_generation_name":
plan.setNetwork_generation_(reader.nextString());
break;
case "partner_plan_id":
plan.setPartner_plan_id(reader.nextString());
break;
case "payment_level":
plan.setPayment_level(reader.nextString());
break;
case "payment_level_id":
plan.setPayment_level_id(reader.nextInt());
break;
case "roaming_amount":
plan.setRoaming_amount(reader.nextDouble());
break;
case "savings_amount":
plan.setSavings_amount(reader.nextDouble());
break;
case "savings_avg":
plan.setSavings_avg(reader.nextDouble());
break;
case "savings_percents":
plan.setSavings_percents(reader.nextInt());
break;
default:
Log.d(TAG, "DEFAULT " + reader.peek() + "");
reader.skipValue();
break;
}
} else {
reader.skipValue();
}
}
return plan;
}
}
If you have a very, very large file, I recommend doing this with a custom deserializer using Gson, but I would not use the JsonDeserializer interface; use the TypeAdapter interface as it is more performant (source). I think that #codemonkey has a very good answer, but it is overly complicated and it can be done much more simply. Specifically, you should never be builidng these Strings yourself (with sb.append()) and you should stay away from JsonDeserializer.
First, create your custom TypeAdapter
public class PersonTypeAdapter extends TypeAdapter<Person> {
#Override
public void write(JsonWriter out, Person value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.beginObject();
out.name("name").value(value.name);
out.name("sirname").value(value.sirname);
out.name("details");
out.beginObject();
out.name("social_no").value(value.social_no);
out.name("creadit_card_no").value(value.creadit_card_no);
out.endObject();
out.endObject();
}
#Override
public Person read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
reader.beginObject();
validateName(reader, "name");
String name = reader.nextString();
validateName(reader, "sirname");
String sirname = reader.nextString();
validateName(reader, "details");
reader.beginObject();
validateName(reader, "social_no");
String social_no = reader.nextString();
validateName(reader, "creadit_card_no");
String creadit_card_no = reader.nextString();
reader.endObject();
reader.endObject();
return new Person(name, sirname, social_no, creadit_card_no);
}
private void validateName(JsonReader reader, String string) throws IOException {
String name = reader.nextName();
if(!string.equals(name)) {
throw new JsonSyntaxException("Expected: \"" + string + "\", got \"" + name + "\"");
}
}
}
And, your POJO, obviously:
public class Person {
public final String name;
public final String sirname;
public final String social_no;
public final String creadit_card_no;
public Person(String name, String sirname, String social_no,
String creadit_card_no) {
this.name = name;
this.sirname = sirname;
this.social_no = social_no;
this.creadit_card_no = creadit_card_no;
}
#Override
public String toString() {
return String.format(
"Person [name=%s, sirname=%s, social_no=%s, creadit_card_no=%s]", name,
sirname, social_no, creadit_card_no);
}
}
Then, you can parse the Json from your file using the method here. /test.json is just the example you gave in your question.
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
public class PersonExample {
public static void main(String... args) {
InputStreamReader streamReader = new InputStreamReader(
PersonExample.class.getResourceAsStream("/test.json"));
PeopleWrapper wrapper = parseJSON(streamReader);
System.out.println(wrapper.people);
}
public static class PeopleWrapper {
#SerializedName("people")
public List<Person> people;
}
public static PeopleWrapper parseJSON(Reader jsonInput) {
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Person.class, new PersonTypeAdapter());
Gson gson = builder.create();
PeopleWrapper peopleWrapper = gson.fromJson(jsonInput, PeopleWrapper.class);
return peopleWrapper;
}
}
This program outputs:
[Person [name=test1, sirname=test2, social_no=1234567, creadit_card_no=34582342309], Person [name=test3, sirname=test4, social_no=12345679, creadit_card_no=345823423090]]
So your actual problem is much more complicated than the one you originally described. I will show you a skeleton of the TypeAdapter you need, and you can figure out the rest. Basically, create the Plan object as you've done, and then for each of the outer JSON keys, handle the value.
If it's one line, you can just handle it in the switch statement.
If it's an array or an object, create a helper method to parse that section of the JSON.
You should assume the JSON is well formed and, if it's not, let Gson throw an Exception. Just tell it to expect what's going to come next.
Here's some code to show you the idea:
import java.io.IOException;
import com.google.gson.*;
import com.google.gson.stream.*;
public class PlanTypeAdapter extends TypeAdapter<Plan> {
private final String TAG = PlanTypeAdapter.class.getSimpleName();
#Override
public void write(JsonWriter out, Plan value) throws IOException {
Log.d(TAG, "WRITE");
}
#Override
public Plan read(JsonReader reader) throws IOException {
Log.d(TAG, "READ");
Plan plan = new Plan();
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
reader.setLenient(false);
reader.beginObject();
while (!(reader.peek() == JsonToken.END_OBJECT)) {
switch (reader.nextName()) {
case "national_plan":
handleNationalPlan(reader, plan);
break;
case "bill_total":
handleBillTotal(reader, plan);
break;
case "contract_end":
plan.setContract_end(reader.nextString());
break;
case "data_level_gb":
plan.setData_level_gb(reader.nextString());
break;
case "data_level_id":
plan.setData_level_id(reader.nextInt());
break;
case "days_to_end":
plan.setDays_to_switch(reader.nextInt());
break;
case "direct_from_operator":
plan.setDirect_from_operator(reader.nextBoolean());
break;
case "calculation_amount":
plan.setCalculationAmount(reader.nextDouble());
break;
case "network_generation_name":
plan.setNetwork_generation_(reader.nextString());
break;
case "partner_plan_id":
plan.setPartner_plan_id(reader.nextString());
break;
case "payment_level":
plan.setPayment_level(reader.nextString());
break;
case "payment_level_id":
plan.setPayment_level_id(reader.nextInt());
break;
case "roaming_amount":
plan.setRoaming_amount(reader.nextDouble());
break;
case "savings_amount":
plan.setSavings_amount(reader.nextDouble());
break;
case "savings_avg":
plan.setSavings_avg(reader.nextDouble());
break;
case "savings_percents":
plan.setSavings_percents(reader.nextInt());
break;
case "yearly_id":
case "handset":
case "internals":
case "consumer_id":
case "calculation_details":
case "operator":
case "total":
case "international_plan":
case "contract_length":
case "zone":
case "externals":
case "cancel_fee":
case "transformers":
case "one-offs":
case "flow":
case "roaming_plan":
case "_id":
// You can use this to ignore the keys you don't care about
default:
Log.d(TAG, "DEFAULT " + reader.peek() + "");
reader.skipValue();
break;
}
}
reader.endObject();
return plan;
}
private void handleNationalPlan(JsonReader reader, Plan plan) throws IOException {
reader.beginObject();
while (!(reader.peek() == JsonToken.END_OBJECT)) {
switch(reader.nextName()) {
case "contract_length":
break;
case "name":
break;
case "country":
// etc.
}
}
reader.endObject();
}
private void handleBillTotal(JsonReader reader, Plan plan) throws IOException {
}
// etc.
}
It seems that at the moment Jackson does not support out of the box such feature to map a field from a nested path.
There is an open issue asking for such feature, but it's a question when will it be done.
The opposite, serializing a nested object to the first level properties in json, is possible by using a #JsonUnwrapped annotation.
So, in order to overcome the problem, it seems that the only way is to write a custom deserializer, which you could map to your class, and use it to create an instance of the class as you need it.
There are different ways you can parse json using the gson library. I will give you two examples.
Method 1 - Write a custom deserializer. This technique uses a class to deserialize the person object. The custom deserializer allows you to create any object you want with the json data. Here are the classes needed to do this:
Group.java:
public class Group {
#SerializedName("people")
private List<Person> persons;
public List<Person> getPersons() {
return persons;
}
public void setPersons(List<Person> persons) {
this.persons = persons;
}
#Override
public String toString() {
String NEW_LINE = System.getProperty("line.separator");
StringBuilder sb = new StringBuilder(this.getClass().getName());
sb.append("{");
sb.append(NEW_LINE);
for(Person p : persons){
sb.append(p.toString());
}
sb.append("}");
return sb.toString();
}
}
GsonTest.java:
public class GsonTest {
public static void main(String[] args) {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Person.class, new PersonDeserializer());
Gson gson = gsonBuilder.create();
try {
JsonParser parser = new JsonParser();
Object obj = parser.parse(new FileReader("C://data.json"));
JsonObject jsonObject = (JsonObject) obj;
Group group = gson.fromJson(jsonObject, Group.class);
System.out.println(group.toString());
} catch (JsonIOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonSyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Person.java:
public class Person {
public Person(String name, String sirname, Long social_no, Long creadit_card_no) {
this.name = name;
this.sirname = sirname;
this.social_no = social_no;
this.creadit_card_no = creadit_card_no;
}
private String name;
private String sirname;
private Long social_no;
private Long creadit_card_no;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSirname() {
return sirname;
}
public void setSirname(String sirname) {
this.sirname = sirname;
}
public Long getSocial_no() {
return social_no;
}
public void setSocial_no(Long social_no) {
this.social_no = social_no;
}
public Long getCreadit_card_no() {
return creadit_card_no;
}
public void Long(Long creadit_card_no) {
this.creadit_card_no = creadit_card_no;
}
#Override
public String toString() {
String NEW_LINE = System.getProperty("line.separator");
StringBuilder sb = new StringBuilder(this.getClass().getName());
sb.append("{");
sb.append(NEW_LINE);
sb.append("name: ");
sb.append(name);
sb.append(NEW_LINE);
sb.append("sirname: ");
sb.append(sirname);
sb.append(NEW_LINE);
sb.append("social_no: ");
sb.append(social_no);
sb.append(NEW_LINE);
sb.append("creadit_card_no: ");
sb.append(creadit_card_no);
sb.append(NEW_LINE);
sb.append("}");
sb.append(NEW_LINE);
return sb.toString();
}
}
PersonDeserializer.java
public class PersonDeserializer implements JsonDeserializer<Person> {
public Person deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
String name = jsonObject.get("name").getAsString();
String sirname = jsonObject.get("sirname").getAsString();
JsonObject details = jsonObject.get("details").getAsJsonObject();
Long social_no = details.get("social_no").getAsLong();
Long creadit_card_no = details.get("creadit_card_no").getAsLong();
Person person = new Person(name, sirname, social_no, creadit_card_no );
return person;
}
}
Method 2 - Use the JsonReader class to parse the json data. You do not have to load the entire json file at once with this technique. This is a better way to parse a large amount of data on devices that have limited resources. This code will be harder to maintain if the json structure changes though. My example code was inspired by this article http://developer.android.com/reference/android/util/JsonReader.html. Use the Person class above with this new GsonTest class:
public class GsonTest {
List<Person> people = null;
public GsonTest() {
people = new ArrayList<Person>();
}
public static void main(String[] args) {
GsonTest gt = new GsonTest();
gt.doGson();
}
void doGson() {
try {
InputStream is = GsonTest.class.getResourceAsStream("data.json");
JsonReader jsonReader = new JsonReader(new InputStreamReader(is, "UTF-8"));
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
if (name.equals("people")) {
readPeopleArray(jsonReader);
}
}
jsonReader.endObject();
for(Person p : people){
System.out.println(p.toString());
}
}
catch (NullPointerException e){
e.printStackTrace();
}
catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void readPeopleArray(JsonReader jsonReader) throws IOException {
jsonReader.beginArray();
while (jsonReader.hasNext()) {
readPersonObject(jsonReader);
}
jsonReader.endArray();
}
private void readPersonObject(JsonReader jsonReader) throws IOException {
String name = null;
String sirname = null;
Long social_no = null;
Long creadit_card_no = null;
jsonReader.beginObject();
while(jsonReader.hasNext()){
String key = jsonReader.nextName();
if(key.equals("details")){
jsonReader.beginObject();
while(jsonReader.hasNext()){
String detailKey = jsonReader.nextName();
if(detailKey.equals("social_no")){
social_no = jsonReader.nextLong();
}
else if(detailKey.equals("creadit_card_no")){
creadit_card_no = jsonReader.nextLong();
}
else{
jsonReader.skipValue();
}
}
jsonReader.endObject();
}
else if(key.equals("name")){
name = jsonReader.nextString();
}
else if(key.equals("sirname")){
sirname = jsonReader.nextString();
}
}
jsonReader.endObject();
people.add(new Person(name, sirname, social_no, creadit_card_no));
}
}
Related
I have written the following code. However I would like to add the items from characters.getData() into a custom array as below so I can then use it to carry out mathematical graphing. How can I create my own custom array list containing settDate, publishingPeriodCommencingTime and publishingPeriodCommencingTime?
while(parser.hasNext()) {
XMLEvent event = parser.nextEvent();
switch(event.getEventType()) {
case XMLStreamConstants.START_ELEMENT:
StartElement startElement = event.asStartElement();
String qName = startElement.getName().getLocalPart();
if (qName.equalsIgnoreCase("settDate")) {
bMarks = true;
} else if (qName.equalsIgnoreCase("publishingPeriodCommencingTime")) {
bLastName = true;
} else if (qName.equalsIgnoreCase("fuelTypeGeneration")) {
bNickName = true;
}
break;
case XMLStreamConstants.CHARACTERS:
Characters characters = event.asCharacters();
if(bMarks) {
System.out.println("settDate: " + characters.getData());
bMarks = false;
}
if(bLastName) {
System.out.println("publishingPeriodCommencingTime: " + characters.getData());
bLastName = false;
}
if(bNickName) {
System.out.println("fuelTypeGeneration: " + characters.getData());
bNickName = false;
}
rollingD subAction= new RollingD(characters.getData(), characters.getData(), characters.getData());
break;
case XMLStreamConstants.END_ELEMENT:
EndElement endElement = event.asEndElement();
if(endElement.getName().getLocalPart().equalsIgnoreCase("item")) {
System.out.println();
}
break;
}
}
This is my custom class
public class RollingD {
private String settDate;
private String publishingPeriodCommencingTime;
private String fuelTypeGeneration;
RollingD(String bMarks, String bLastName, String bNickName) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
public String getSettDate() {
return settDate;
}
public void setSettDate(String settDate) {
this.settDate = settDate;
}
public String getPublishingPeriodCommencingTime() {
return publishingPeriodCommencingTime;
}
public void setPublishingPeriodCommencingTime(String publishingPeriodCommencingTime) {
this.publishingPeriodCommencingTime = publishingPeriodCommencingTime;
}
public String getFuelTypeGeneration() {
return fuelTypeGeneration;
}
public void setFuelTypeGeneration(String fuelTypeGeneration) {
this.fuelTypeGeneration = fuelTypeGeneration;
}
}
This is a sample of the XML
<settDate>2020-02-29</settDate>
<publishingPeriodCommencingTime>09:55:00</publishingPeriodCommencingTime>
<fuelTypeGeneration>31891</fuelTypeGeneration>
<settDate>2020-02-29</settDate>
<publishingPeriodCommencingTime>10:00:00</publishingPeriodCommencingTime>
<fuelTypeGeneration>31743</fuelTypeGeneration>
..
Below is my implementation according to how I understood your question.
I created the following XML file that contains only the sample data from your question.
<?xml version="1.0" encoding="UTF-8"?>
<root>
<settDate>2020-02-29</settDate>
<publishingPeriodCommencingTime>09:55:00</publishingPeriodCommencingTime>
<fuelTypeGeneration>31891</fuelTypeGeneration>
<settDate>2020-02-29</settDate>
<publishingPeriodCommencingTime>10:00:00</publishingPeriodCommencingTime>
<fuelTypeGeneration>31743</fuelTypeGeneration>
</root>
Through experimentation, I saw that the effective order of the XML events is:
START_ELEMENT
CHARACTERS
END_ELEMENT
The elements of interest are:
settDate
publishingPeriodCommencingTime
fuelTypeGeneration
The basic algorithm is therefore:
If event type is START_ELEMENT and event name is settDate, create a new instance of class RollingD.
If event type is CHARACTERS, then set the value of the member in RollingD according to the event name.
If event type is END_ELEMENT and event name is fuelTypeGeneration, add the RollingD object to the list.
Note that you need to replace path-to-XML-file in the below code with the actual path to your XML file.
Also, method toString() in class RollingD is purely for debugging purposes and therefore can safely be removed from the below code if you think you don't need it.
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
public class StaxTest {
private static final String SETT_DATE = "settDate";
private static final String PUBLISHING_PERIOD_COMMENCING_TIME = "publishingPeriodCommencingTime";
private static final String FUEL_TYPE_GENERATION = "fuelTypeGeneration";
public static void main(String[] args) {
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
XMLEventReader reader = null;
Path path = Paths.get("path-to-XML-file");
try (FileInputStream fis = new FileInputStream(path.toFile())) {
reader = xmlInputFactory.createXMLEventReader(fis);
List<RollingD> list = new ArrayList<>();
RollingD rD = null;
String localName = null;
while (reader.hasNext()) {
XMLEvent event = reader.nextEvent();
switch (event.getEventType()) {
case XMLEvent.START_ELEMENT:
StartElement elem = event.asStartElement();
QName qName = elem.getName();
localName = qName.getLocalPart();
switch (localName) {
case SETT_DATE:
rD = new RollingD();
break;
case PUBLISHING_PERIOD_COMMENCING_TIME:
break;
case FUEL_TYPE_GENERATION:
break;
default:
}
break;
case XMLEvent.END_ELEMENT:
EndElement endElem = event.asEndElement();
QName qNamEnd = endElem.getName();
String endName = qNamEnd.getLocalPart();
switch (endName) {
case SETT_DATE:
break;
case PUBLISHING_PERIOD_COMMENCING_TIME:
break;
case FUEL_TYPE_GENERATION:
list.add(rD);
break;
default:
}
break;
case XMLEvent.CHARACTERS:
Characters chars = event.asCharacters();
if (!chars.isWhiteSpace()) {
String data = chars.getData();
switch (localName) {
case SETT_DATE:
rD.setSettDate(data);
break;
case PUBLISHING_PERIOD_COMMENCING_TIME:
rD.setPublishingPeriodCommencingTime(data);
break;
case FUEL_TYPE_GENERATION:
rD.setFuelTypeGeneration(data);
break;
default:
}
}
break;
default:
System.out.println("Unhandled XML event: " + event.getEventType());
}
}
list.stream().forEach(System.out::println); // Prints the list.
}
catch (IOException | XMLStreamException x) {
x.printStackTrace();
}
finally {
if (reader != null) {
try {
reader.close();
}
catch (XMLStreamException xXmlStream) {
System.out.println("WARNING (ignored): Failed to close XML event reader");
xXmlStream.printStackTrace();
}
}
}
}
}
class RollingD {
private String settDate;
private String publishingPeriodCommencingTime;
private String fuelTypeGeneration;
public RollingD() {
this(null, null, null);
}
public RollingD(String settDate,
String publishingPeriodCommencingTime,
String fuelTypeGeneration) {
this.settDate = settDate;
this.publishingPeriodCommencingTime = publishingPeriodCommencingTime;
this.fuelTypeGeneration = fuelTypeGeneration;
}
public void setSettDate(String settDate) {
this.settDate = settDate;
}
public void setPublishingPeriodCommencingTime(String publishingPeriodCommencingTime) {
this.publishingPeriodCommencingTime = publishingPeriodCommencingTime;
}
public void setFuelTypeGeneration(String fuelTypeGeneration) {
this.fuelTypeGeneration = fuelTypeGeneration;
}
public String toString() {
return String.format("%s,%s,%s",
settDate,
publishingPeriodCommencingTime,
fuelTypeGeneration);
}
}
Here is the output I get after running the above code.
2020-02-29,09:55:00,31891
2020-02-29,10:00:00,31743
I need to convert a JSON response into Java Object, but I am gettin nullpointerException.
Here is my model class:
public class Cheque {
private String payeeName;
private String accountNumber;
private String ifsCode;
private String micr;
private String bankName;
public Cheque() {
super();
// TODO Auto-generated constructor stub
}
public Cheque(String payeeName, String accountNumber, String ifsCode, String micr, String bankName) {
super();
this.payeeName = payeeName;
this.accountNumber = accountNumber;
this.ifsCode = ifsCode;
this.micr = micr;
this.bankName = bankName;
}
public String getPayeeName() {
return payeeName;
}
public void setPayeeName(String payeeName) {
this.payeeName = payeeName;
}
public String getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
public String getIfsCode() {
return ifsCode;
}
public void setIfscCode(String ifsCode) {
this.ifsCode = ifsCode;
}
public String getMicr() {
return micr;
}
public void setMicr(String micr) {
this.micr = micr;
}
public String getBankName() {
return bankName;
}
public void setBankName(String bankName) {
this.bankName = bankName;
}
Below I am posting the method in which I am invoking a Python program and getting a Json response from it:
public class RunPython {
public static void main(String[] args) throws IOException,ScriptException,NullPointerException{
// TODO Auto-generated method stub
Process p = Runtime.getRuntime().exec("python <path to file>/reg.py");
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line ;
try {
while((line =in.readLine()) != null) {
System.out.println(line);
}
} finally {
in.close();
}
ObjectMapper mapper = new ObjectMapper();
try {
Cheque cheque = mapper.readValue(line, Cheque.class);
System.out.println("Java object :");
System.out.println(cheque);
}
catch (JsonGenerationException ex) {
ex.printStackTrace();
}
catch (JsonMappingException ex) {
ex.printStackTrace();
}
catch (IOException ex) {
ex.printStackTrace();
}}}
The JSON response which I am getting is:
{
"bankName": [
"Bank"
],
"accountNumber": [
"989898989898"
],
"ifsCode": [
"0000000"
],
"micr": [
"0000000"
],
"payeeName": [
"name"
]
}
After running the program I am getting the JSON response as expected, but while converting it to a Java object it is showing nullPointerException in the main thread. Help me out to find where I am making the mistake.
You consume/exhaust all your Process Inputstream here when printing it :
try {
while((line =in.readLine()) != null) {
System.out.println(line);
}
And later on when you call the below it's already null :
Cheque cheque = mapper.readValue(line, Cheque.class);
You'd have to process it in the above while loop, instead of only printing it out
When you reach the statement:
Cheque cheque = mapper.readValue(line, Cheque.class);
variable line is null.
So you can either rebuild the JSON string (with a StringBuilder), or remove the code that prints the response, and parse the JSON directly from p.getInputStream().
Your Java object has String value, but JSON has array type ([ ])
[Unable to access property of another object stored in Arraylist]
I am creating an function to get JSON input in object from RESTful Web service input and format it again in JSON format to call other web service.
I have limitation that I can not use any JSON API for object mapping hence using Java reflection core API.
I am able to create JSON format from Input for simple elements but unable to access nested elements (another user defined POJO class ). I am using arraylist.
Input
{
"GenesisIncidents": {
"service": "Transmission",
"affectedCI": "22BT_ORNC03",
"opt_additionalAffectedItems": [
{
"itemType": "NODE-ID",
"ItemName": "22BT_ORNC03"
},
{
"ItemType": "CCT",
"ItemName": "A_circuit_id"
}]
}
}
GenesisIncidents.class
import java.util.ArrayList;
import java.util.Date;
public class GenesisIncidents {
private String service;
private String affectedCI;
private ArrayList<AdditionalAffectedItems> opt_additionalAffectedItems;
public GenesisIncidents(){}
public String getService() {
return service;
}
public void setService(String service) {
this.service = service;
}
public String getAffectedCI() {
return affectedCI;
}
public void setAffectedCI(String affectedCI) {
this.affectedCI = affectedCI;
}
public ArrayList<AdditionalAffectedItems> getOpt_additionalAffectedItems() {
return opt_additionalAffectedItems;
}
public void setOpt_additionalAffectedItems(ArrayList<AdditionalAffectedItems> opt_additionalAffectedItems) {
this.opt_additionalAffectedItems = opt_additionalAffectedItems;
}
}
AdditionalAffectedItems.class
public class AdditionalAffectedItems {
private String itemType;
private String itemName;
public AdditionalAffectedItems(){
super();
}
public String getItemType() {
return itemType;
}
public void setItemType(String itemType) {
this.itemType = itemType;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
}
Implemetation
public void updateTicketExt(GenesisIncidents genesisIncidents) {
try{
Field allFields[]=genesisIncidents.getClass().getDeclaredFields();
Method allMethods[] = genesisIncidents.getClass().getDeclaredMethods();
String jsonString ="{\r\n \""+genesisIncidents.getClass().getName().toString().substring(48)+"\": {";
final String preStr="\r\n \""; //To create a JSON object format.
final String postStr="\": "; //To create a JSON object format.
int totalNoOfFields=allFields.length;
for (Field field : allFields) {
System.out.println(field.getType());
String getter="get"+StringUtils.capitalize(field.getName());
Method method= genesisIncidents.getClass().getMethod(getter, null);
try{
if(field.getType().toString().contains("Integer"))
jsonString=jsonString + preStr + field.getName() + postStr +method.invoke(genesisIncidents).toString()+",";
else
jsonString=jsonString + preStr + field.getName() + postStr +"\""+method.invoke(genesisIncidents).toString()+"\",";
if(field.getType().toString().contains("ArrayList")){
System.out.println("ArrayListElement found");
genesisIncidents.getOpt_additionalAffectedItems().forEach(obj->{System.out.println(obj.getItemName());});
//convertArrayToJSON(field, genesisIncidents);
}
}catch(NullPointerException npe)
{
System.out.println("Null value in field.");
continue;
}
}
jsonString=jsonString.substring(0,jsonString.length()-1);
jsonString=jsonString+"\r\n }\r\n }";
System.out.println("\n"+jsonString);
}catch(Exception jex){
jex.printStackTrace();
}
}
My below code line is unable to access object stored under array list.
genesisIncidents.getOpt_additionalAffectedItems().forEach(obj->{System.out.println(obj.getItemName());});
OUTPUT
karaf#root>class java.lang.String
class java.lang.String
class java.lang.String
class java.util.ArrayList
ArrayListElement found
null
null
{
"GenesisIncidents": {
"service": "Transmission",
"affectedCI": "22BT_ORNC03",
"opt_additionalAffectedItems": " [org.apache.servicemix.examples.camel.rest.model.AdditionalAffectedItems#5881a 895, org.apache.servicemix.examples.camel.rest.model.AdditionalAffectedItems#399b4e eb]"
}
}
I have fiddled around with your example I have managed to get it working. This will produce the correct JSON string by passing in an instance of a GenesisIncident object. I guess that there is much room for improvement here but this can serve as an example.
public static String genesisToJson(GenesisIncidents incidents) {
try{
StringBuilder jsonBuilder = new StringBuilder();
jsonBuilder.append("{\r\n \"")
.append(incidents.getClass().getSimpleName())
.append("\": {");
Field allFields[] = incidents.getClass().getDeclaredFields();
for (Field field : allFields) {
String getter = getGetterMethod(field);
Method method = incidents.getClass().getMethod(getter, null);
try{
if(field.getType().isAssignableFrom(Integer.class)) {
jsonBuilder.append(preStr).append(field.getName()).append(postStr)
.append(method.invoke(incidents).toString()).append(",");
} else if (field.getType().isAssignableFrom(String.class)) {
jsonBuilder.append(preStr).append(field.getName()).append(postStr).append("\"")
.append(method.invoke(incidents).toString()).append("\",");
} else if (field.getType().isAssignableFrom(List.class)) {
System.out.println("ArrayListElement found");
getInnerObjectToJson(field, incidents.getOptItems(), jsonBuilder);
}
} catch(NullPointerException npe) {
System.out.println("Null value in field.");
continue;
}
}
jsonBuilder.append("\r\n } \r\n }");
return jsonBuilder.toString();
}catch(Exception jex){
jex.printStackTrace();
}
return null;
}
private static void getInnerObjectToJson(Field field, List<AdditionalAffectedItems> items, StringBuilder builder)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
builder.append(preStr).append(field.getName()).append(postStr).append("[");
for (var item : items) {
var fields = List.of(item.getClass().getDeclaredFields());
builder.append("{");
for (var f : fields) {
String getter = getGetterMethod(f);
Method method = item.getClass().getMethod(getter, null);
builder.append(preStr).append(f.getName()).append(postStr).append("\"")
.append(method.invoke(item).toString()).append("\"");
if (!(fields.indexOf(f) == (fields.size() - 1))) {
builder.append(",");
}
}
if (items.indexOf(item) == (items.size() - 1)) {
builder.append("}\r\n");
} else {
builder.append("},\r\n");
}
}
builder.append("]");
}
private static String getGetterMethod(Field field) {
return "get" + StringUtils.capitalize(field.getName());
}
I have a program that reads in a simple JSON file and manipulates the data. I then store this data in trees (albeit badly). I have a problem where arguments can longs e.g {1,2}, longs and variables e.g {1,x2}, or variables with other variables e.g. {x1,x2}.
I have been able to retrieve the variables from the JSONArray. The problem arises when I have a variable and a value. I can't for the life of me figure out how to deal with such an occurrence. I apologise for the excessive use of try-catch operations. If anyone could help me solve this issue, it would be much appreciated.
public class program {
public static void main(String[] args) throws IOException {
File file = new File();
File outputfile = new File();
PrintWriter pw = new PrintWriter(new BufferedWriter(new
FileWriter(outputfile, true)));
JSONParser parser = new JSONParser();
try {
// creates object of parsed file
Object object = parser.parse(new FileReader(file));
// casts object to jsonObject
JSONObject jsonObject = (JSONObject) object;
// gets declaration-list JSONArray from the object created.
JSONArray jsonArray = (JSONArray) jsonObject.get("declaration-list");
// Surrounding this in a try-catch would allow me to deal with the
// different value cases unlike the frist time i wrote it
try {
/*
* iterator to cycle through the array. Made the mistake last
* time of continuously calling a method
*/
Iterator iterator = jsonArray.iterator();
while (iterator.hasNext()) {
JSONObject jo = (JSONObject) iterator.next();
String variableName = (String) jo.get("declared-variable");
MyTreeNode<String> root = new MyTreeNode<>(variableName);
try {
long value = (long) jo.get("value");
MyTreeNode<Long> child1 = new MyTreeNode(value);
System.out.println(root.getData());
root.addChild(child1);
for (MyTreeNode node : root.getChildren()) {
System.out.println(node.getData());
}
test.put(variableName, value);
// numPrint(test, variableName, pw);
} catch (Exception e) {
final JSONObject jsonValue = (JSONObject) jo.get("value");
final String operator = (String) jsonValue.get("operator");
final JSONArray arguments = (JSONArray) jsonValue.get("arguments");
ArrayList values[] = new ArrayList[arguments.size()];
if (operator.equals("set")) {
for(int i = 0; i < arguments.size(); i++){
try{
//prints nested variables
JSONObject jtest = (JSONObject) arguments.get(i);
String varval = (String) jtest.get("variable");
System.out.println(varval);
}catch(Exception g){
}
}
MyTreeNode<myObject> test1 = new MyTreeNode(new myObject(operator, arguments));
root.addChild(test1);
for (MyTreeNode node : root.getChildren()) {
System.out.print(root.getData());
System.out.print(" = ");
System.out.println(node.getData());
}
}
if (operator.equals("pair")) {
MyTreeNode<myObject> test1 = new MyTreeNode(new myObject(operator, arguments));
root.addChild(test1);
for (MyTreeNode node : root.getChildren()) {
System.out.print(root.getData() + " = ");
System.out.println(node.getData());
}
}
}
}
} catch (Exception e) {
System.out.println("oops");
}
} catch (FileNotFoundException e) {
System.out.println("Input file not found");
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParseException e) {
System.out.println("File was not parsed");
e.printStackTrace();
}
pw.flush();
pw.close();
}
}
class MyTreeNode<T> {
private T data = null;
private List<MyTreeNode> children = new ArrayList<>();
private MyTreeNode parent = null;
public MyTreeNode(T data) {
this.data = data;
}
public void addChild(MyTreeNode child) {
child.setParent(this);
this.children.add(child);
}
public void addChild(T data) {
MyTreeNode<T> newChild = new MyTreeNode<>(data);
newChild.setParent(this);
children.add(newChild);
}
public void addChildren(List<MyTreeNode> children) {
for (MyTreeNode t : children) {
t.setParent(this);
}
this.children.addAll(children);
}
public List<MyTreeNode> getChildren() {
return children;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
private void setParent(MyTreeNode parent) {
this.parent = parent;
}
public MyTreeNode getParent() {
return parent;
}
}
class myObject {
String operator;
JSONArray arguments;
public myObject(String operator, JSONArray arguments) {
this.operator = operator;
this.arguments = arguments;
}
public JSONArray get() {
return arguments;
}
public String toString() {
if (arguments.size() == 0) {
return "{}";
}
if (operator.equals("pair")) {
return "(" + arguments.get(0) + "," + arguments.get(1) + ")";
} else if (operator.equals("set")) {
String concat = "{" + arguments.get(0);
for (int i = 1; i < arguments.size(); i++) {
concat += "," + arguments.get(i);
}
return concat += "}";
}
return "wot";
}
}
In order to process the JSONArray, I suggest that you create a method which checks the type of the object first and then delegates the processing to other specialised methods based on its type.
This will allow you re-use the code in case you have arrays in arrays and also to navigate through the JSON tree.
Something along these lines:
private static void processArray(JSONArray jsonArray) {
jsonArray.forEach(o -> {
if (o instanceof Number) {
processNumber((Number) o);
} else if (o instanceof JSONObject) {
process((JSONObject) o);
} else if (o instanceof String) {
process((String) o);
} else if (o instanceof JSONArray) {
processArray((JSONArray) o); // recursive call here.
}
});
}
Other methods would look like:
private static void process(String o) {
System.out.println(o); // just an example
}
public static void processNumber(Number number) {
System.out.println(number); // just an example
}
And the most complex would be the one for processing objects:
private static void process(JSONObject o) {
o.forEach((s, o1) -> {
System.out.println(s);
if (o1 instanceof Number) {
processNumber((Number) o1);
} else if (o1 instanceof JSONObject) {
process((JSONObject) o1); // recursion
} else if (o1 instanceof String) {
process((String) o1);
} else if (o1 instanceof JSONArray) {
processArray((JSONArray) o1);
}
});
}
This method would also be recursive. With this type of approach you can navigate through all objects in the tree.
Update:
If you want to process JSON like:
{
"declared-variable": "x17",
"value": {
"operator": "set",
"arguments": [
1,
2,
{
"variable": "x8"
}
]
}
}
you can do so by creating a main method similar to this one:
public static void main(String[] args) throws IOException, ParseException {
JSONParser jsonParser = new JSONParser(JSONParser.MODE_JSON_SIMPLE);
try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("array_mixed.json")) {
Object obj = jsonParser.parse(in);
if (obj instanceof JSONArray) {
processArray((JSONArray) obj);
}
else if(obj instanceof Object) {
process((JSONObject) obj);
}
}
}
This main method together with the other methods described can at least print out all the elements in the JSON.
You should be able to at least print out the following in the case of the specified JSON above:
declared-variable
x17
value
arguments
1
2
variable
x8
operator
set
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public List readJsonStream(InputStream in) throws IOException {
JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
try {
return readMessagesArray(reader);
} finally {
reader.close();
}
}
public List readMessagesArray(JsonReader reader) throws IOException {
List messages = new ArrayList();
reader.beginArray();
while (reader.hasNext()) {
messages.add(readMessage(reader));
}
reader.endArray();
return messages;
}
public Message readMessage(JsonReader reader) throws IOException {
long id = -1;
String text = null;
User user = null;
List geo = null;
reader.beginObject();
while (reader.hasNext()) {
String name = reader.nextName();
if(name.equals("id")) {
id = reader.nextLong();
} else if (name.equals("text")) {
text = reader.nextString();
} else if (name.equals("geo") && reader.peek() != JsonToken.NULL) {
geo = readDoublesArray(reader);
} else if (name.equals("user")) {
user = readUser(reader);
} else {
reader.skipValue();
}
}
reader.endObject();
return new Message(id, text, user, geo);
}
public List readDoublesArray(JsonReader reader)throws IOException {
List doubles = new ArrayList();
reader.beginArray();
return doubles;
}
public User readUser(JsonReader reader) throws IOException {
String username = null;
int followersCount = -1;
reader.beginObject();
while (reader.hasNext()) {
String name = reader.nextName();
if(name.equals("name")) {
username = reader.nextString();
} else if (name.equals("followers_count")) {
followersCount = reader.nextInt();
} else {
reader.skipValue();
}
}
reader.endObject();
return new User(username, followersCount);
}}
I'm using the exact example from http://developer.android.com/reference/android/util/JsonReader.html. However, there is a problem with "User cannot be resolved to a type".
'User' class in the given example is just to show how it may work. You may substitute it with something like this:
public class User{
String name;
int followers_count;
public User(String name, int followers_count){
this.name=name;
this.followers_count=followers_count;
}
}