As the title says I am not able to deserialize a whole JSON file into an ArrayList, and more specifically, my code reads only the first item from the file and ignores the rest.
This is my writing method:
private static void writeJSON(MyClass myClassObject) throws JsonGenerationException, JsonMappingException, IOException {
ObjectMapper mapper = new ObjectMapper();
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("myclass.json", true)));
mapper.writeValue(out, myClassObject);
}
I call this method in my main code whenever I want to serialize an object, and it works fine.
This is my reading method:
private static void readFromFile() throws IOException {
String jsonString = FileUtils.readFileToString(new File("myclass.json"), StandardCharsets.UTF_8);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
ArrayList<MyClass> myClassArray = mapper.readValue(jsonString, new TypeReference<ArrayList<MyClass>>() {});
}
Before adding this part
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
and a default constructor in MyClass class, I was getting some exceptions and more specifically the "Can not deserialize instance of java.util.ArrayList out of START_OBJECT token"
However, now it works without any errors or exceptions, BUT, by printing my myClassArray ArrayList I realized that it contained only the first object (and its values). Trying to figure out the problem I noticed that if I print the jsonString value I get the whole JSON file (as a String).
So I guess the problem is related with this part of the code
ArrayList<MyClass> myClassArray = mapper.readValue(jsonString, new TypeReference<ArrayList<MyClass>>() {});
but I can't figure it out.
MyClass class looks like this:
public class MyClass {
private String name;
private String country;
private double features[];
private Date timestamp = new Date();
public City() { //The empty constructor is used for the needs of the readFromFile method in Main class.
}
public City(String name, String country) {
super();
this.name = name;
this.country = country;
}
public City(String name,String country,double[] features) {
this.name = name;
this.country = country;
this.features = Arrays.copyOf(features, features.length);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public double[] getFeatures() {
return Arrays.copyOf(features, features.length);
}
public void setFeatures(double[] features) {
this.features = features;
}
public Date getTimestamp() {
return timestamp;
}
public void setTimestamp(Date timestamp) {
this.timestamp = timestamp;
}
and the JSON file right now (ignore the zeros and the numbers, the whole thing is semi-completed):
{"name":"John","country":"gr","features":[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.7123809523809526,0.75,0.0],"timestamp":1637924593676}{"name":"Scott","country":"gb","features":[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.6598639455782312,0.2,0.15601209271073035],"timestamp":1637924610010}
{"name":"Michael","country":"it","features":[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.6877551020408165,0.75,0.06856164464370273],"timestamp":1638458784201}
UPDATE: I fixed my writing method and it looks like this:
private static void writeJSON(MyClass myClassObject) throws JsonGenerationException, JsonMappingException, IOException {
List<MyClass> objectsToSerialize = new ArrayList<>();
objectsToSerialize.add(myClassObject);
ObjectMapper mapper = new ObjectMapper();
FileWriter out = new FileWriter("myclass.json", true);
mapper.writeValue(out, objectsToSerialize);
}
and it seems that it fixes the way my JSON file should look.
[{"name":"John","country":"gr","features":[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.6987074829931972,0.2,0.0],"timestamp":1638466420015}][{"name":"Scott","country":"gb","features":[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.6181632653061225,0.08,0.15601209271073035],"timestamp":1638466428309}][{"name":"Michael","country":"it","features":[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.6884353741496598,0.75,0.06856164464370273],"timestamp":1638466987235}]
However, the initial problem still exists. I think that's because whenever I write to the JSON file I append to the file, so each object apart the first one(that it wasn't needed to append since it's the first item to be written inside the file) doesn't get recognized as a JSON object because it's technically outside the JSON frame. I know one solution is to add all objects at once but I don't want that because my program runs in a loop and I call my writing method multiple times, adding a different object each time.
So how I'm actually going to "add" objects into the JSON file instead of "writing" them?
CodePudding user response:
Your JSON file is not valid. You only have a couple of JSON objects, but you need to bundle them together in a JSON Array as follows:
[
{
"name": "John",
"country": "gr",
"features": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.7123809523809526,
0.75,
0.0
],
"timestamp": 1637924593676
},
{
"name": "Scott",
"country": "gb",
"features": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.6598639455782312,
0.2,
0.15601209271073035
],
"timestamp": 1637924610010
},
{
"name": "Michael",
"country": "it",
"features": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.6877551020408165,
0.75,
0.06856164464370273
],
"timestamp": 1638458784201
}
]
In order to fix your writing method you need to provide it with a list of MyClass
objects instead of a single one at a time (you don't need to append while writing with this solution):
public class Main {
public static void main(String[]args) throws IOException {
List<MyClass> objectsToSerialize = new ArrayList<>();
objectsToSerialize.add(new MyClass("Name1", "Country1", new double[] { 1.0 }));
objectsToSerialize.add(new MyClass("Name2", "Country2", new double[] { 2.0 }));
objectsToSerialize.add(new MyClass("Name3", "Country3", new double[] { 3.0 }));
ObjectMapper mapper = new ObjectMapper();
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("myclass.json")));
mapper.writeValue(out, objectsToSerialize);
}
}
This means your method must accept a list of MyClass
and not a single MyClass
:
private static void writeJSON(List<MyClass> objectsToSerialize) throws IOException {
ObjectMapper mapper = new ObjectMapper();
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("myclass.json")));
mapper.writeValue(out, objectsToSerialize);
}
If you need to continuously add content to your JSON file you could do as follows:
public class Main {
public static void main(String[]args) throws IOException {
// Read the file
List<MyClass> myClasses = readFromFile();
// Add whatever MyClass objects you want to the read List
myClasses.add(new MyClass("Name1", "Country1", new double[] { 1.0 }));
myClasses.add(new MyClass("Name2", "Country2", new double[] { 2.0 }));
myClasses.add(new MyClass("Name3", "Country3", new double[] { 3.0 }));
// Write the whole List again
writeJSON(myClasses);
}
private static List<MyClass> readFromFile() throws IOException {
String jsonString = FileUtils.readFileToString(new File("myclass.json"), StandardCharsets.UTF_8);
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(jsonString, new TypeReference<List<MyClass>>() {});
}
private static void writeJSON(List<MyClass> objectsToSerialize) throws IOException {
ObjectMapper mapper = new ObjectMapper();
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("myclass.json")));
mapper.writeValue(out, objectsToSerialize);
}
}
CodePudding user response:
Your json file does not contain valid json array. It should looks like:
[
{ ... },
{ ... }
]
Not
{ ... }
{ ... }
I think you wrote json as single objects, not as array.
CodePudding user response:
I will assume that the mapper you are using is Jackson's Object Mapper
. In your line of code:
ArrayList<MyClass> myClassArray = mapper.readValue(jsonString, new TypeReference<ArrayList<MyClass>>() {});
there is no real error. Rather, the method with which you corrected your prior error is flawed:
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
You are just bypassing the initial error, the problem is that your JSON is incorrectly formatted, and so it cannot be casted into a Collection. Check your original file, or put the string into an online JSON formatter to verify it is valid. Here is a potential link: https://jsonlint.com/.