I have a form that allows me to input data about a single Item. Every time someone submits an Item, I want to add it to a JSON array, which is stored in a file.
Here's my code:
for (Item obj : list) {
out.print(obj.getId());
out.println("");
out.print(obj.getProductName());
out.println("");
out.print(obj.getPrice());
out.println("");
out.print(obj.getType());
out.println("");
}
ObjectMapper mapper = new ObjectMapper();
File file=new File("D:\\extern_2\\src\\java\\JSON\\jsonlist.json");
if (!file.exists()) {
file.createNewFile();
}
PrintWriter print = new PrintWriter(new BufferedWriter(new FileWriter(file, true)));
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.writerWithDefaultPrettyPrinter().writeValue(print, list);
The problem is that every time I add a new Item, a new JSON array is created and appended to the existing file contents.
Desired output:
[ {
"id" : 56,
"productname" : "kklll",
"price" : "56",
"type" : "Hot Coffee",
"productName" : "kklll"
} , {
"id" : 89,
"productname" : "llll",
"price" : "43",
"type" : "Drinks",
"productName" : "llll"
} ]
Actual output:
[ {
"id" : 56,
"productname" : "kklll",
"price" : "56",
"type" : "Hot Coffee",
"productName" : "kklll"
} ][ {
"id" : 89,
"productname" : "llll",
"price" : "43",
"type" : "Drinks",
"productName" : "llll"
} ]
Why is it appending a new array instead of adding my new Item to the existing array?
Look at the FileWriter you are creating: new FileWriter(file, true). That second parameter tells the FileWriter to simply append information to the end of the file. If you are modifying existing JSON, you will need to overwrite the file every time. This means that the first time you create an Item, the ObjectMapper will write it out as a valid JSON string, representing an array with a single object. The second time you create an Item, it will do the same thing for your new object, creating an array with only one object (the second Item) and writing it to the file, even though that file already contains an array. At no point are you actually looking at the file to see if it contains any existing data. You are also not parsing your file into JSON, which would allow you to take an existing JSON array and add something to it.
Your process should be like this:
Read in your existing data in your file, using the ObjectMapper. Since your file contains an array of Item objects, you should end up with a List<Item> after you've read in your file
Add your new Item to the List
Convert your List<Item> to JSON and write it to your .json file. Make sure to overwrite your .json file, not just append to it.
Related
I have a json file which is mostly standard for all my work, the only difference is few parameters.
Now I want to know how can I using java use this json file as a template and provide the parameters as input and save the new json file on local directory?
{
"key" : "HWM_NAME",
"value" : "PINE_SLS_SVC_CUST_CNTCT"
}, {
"key" : "TOPIC",
"value" : "SLS_SVC_CUST_CNTCT2"
}, {
"key" : "SRC_SCHEMA",
"value" : "party_pkg"
}, {
"key" : "SRC_TABLE",
"value" : "SLS_SVC_CUST_CNTCT"
}, {
"key" : "TGT_SCHEMA",
"value" : "mstrdata_hub"
}, {
"key" : "TGT_TABLE",
"value" : "SLS_SVC_CUST_CNTCT"
} ]
},
So here I wish to just change the Value: "PINE_SLS_SVC_CUST_CNTCT" to some other value that I would take as input from user and give me a new json file with those values.
PS: I am working on Java Swing to create a GUI to get the parameters from the user and provide the json file as output.enter image description here
this is how GUI looks
Consider using some JSON Library, for example GSon
Read the values from json
List<LinkedTreeMap> values = gson.fromJson(json, ArrayList.class);
...
update the values, here you can write values from UI components!!!!
for (LinkedTreeMap pair : values) {
//Update values
System.out.println(pair.toString());
}
And generate JSON from java objects
import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
...
Gson gson = new Gson();
String json = gson.toJson(values);
I'm not sure about how to store data about individual users in a golf program that I'm designing (each user needs to have their previous holes etc tracked and logged) in Java
I was wondering if there is a way to store this data without needing to create an individual file for each user?
Any help is much appreciated!
Thanks
You could store this as JSON instead, E.G:
{
"Arnold Palmer" : {
"handicap" : "2",
"history" : {
"1" : {
"courseName" : "St Andrews",
"holeNumber" : "1",
"score" : "2"
},
"2" : {
"courseName" : "St Andrews",
"holeNumber" : "2",
"score" : "3"
}
... etc
}
},
"Tiger Woods" : {
"handicap" : "4",
"history" : {
"1" : {
"courseName" : "Pebble Beach",
"holeNumber" : "1",
"score" : "4"
},
"2" : {
"courseName" : "Pebble Beach",
"holeNumber" : "2",
"score" : "6"
}
... etc
}
}
Then, just parse it when the program starts up and extract the info you need for that user (there are libraries you can use for this). I would suggest that JSON is a more suitable data format for your needs as you need to store dynamic, graph-like data. CSV files are excellent for more simple data sets.
I would still think it better to keep to a seperate file per user though as it will save you having to read through one huge file to find the data you need. Depends how many users you will have though.
Also, if you need to persist data between users, have a shared file for this (e.g. highscores).
If you don't need the files to be exported to another program/system, you can stop caring about its format and start thinking about creating a class hierarchy for your model, which eventually will rely upon Java object serialization:
Writing objects to a file:
MyObject obj1=...;
MyObject obj2=...;
try (ObjectOutputStream output=new ObjectOutputStream(new FileOutputStream(file)))
{
output.writeObject(obj1);
output.writeObject(obj2);
}
Reading objects from a file:
try (ObjectInputStream input=new ObjectInputStream(new FileInputStream(file)))
{
MyObject obj=(MyObject)input.readObject();
}
You just need to ensure that your class (MyObject in the upper example) implements java.io.Serializable, as well as every class involved in its definition (member variables and its subsequent definitions).
You can calso serialize/parse a collection of objects, as long as you chose a serializable implementation of Collection (for example java.util.ArrayList).
In Java the easiest way to store key-value pairs are properties files, e. g.:
Write:Properties prop = new Properties();
prop.setProperty("user1.prevHole", "foo");
prop.store(new FileOutputStream("golf.properties"), null);
Read:Properties prop = new Properties();
prop.load(new FileInputStream("golf.properties"));
String prevHole = prop.getProperty("user1.prevHole");
See Java Properties file examples
Here is my document :
{ "_id" : ObjectId("5495cfcaec1e18b48015bba3"),
"Type" : "1",
"DomainSize" : "60",
"Metadata" : { "visit" : "3550",
"website" : "1",
"Specifics" : { "Size:" : "2",
"Type:" : "Janes",
"Closure Type:" : "Slip-On"},
"cat" : "2",
"function" : "6"},
"rate" : " 95.5% "}
I want to update few keys from Metadata which I don't know in advance.
My input is a Map of keys and values that exist inside the Metadata list.
I'm wrapping up the given map with another Map that the key is "Metadata" and the value the given map.
Map<String,Map<String,String>> metadata =new HashMap();
metadata.put("Metadata", values);
So I'm ending up with a
<"Metadata", Map<Key,Value>>
Then I used the following:
m_collection.update(new BasicDBObject("_id",id) , new BasicDBObject("$set", new BasicDBObject(metadata)));
The record update the existing keys inside the nested map adding '[]' to each value and deleting all the keys that are not been update.
For an example the given map is {'visit': '3558' , 'website' : '20'}.
After an updated I'm ending up with:
{ "_id" : ObjectId("5495cfcaec1e18b48015bba3"),
"Type" : "1",
"DomainSize" : "60",
"Metadata" : { "visit" : ["3558"],
"website" : ["20"]},
"rate" : " 95.5% "}
What did I do wrong?
You're calling $set on "metadata" which discards whatever is there and sets the new value with whatever you pass in. If you only want to partially update a document like that that, you'll either have to pass a complete document to reflect the new state or just issue $set updates: one for each field to change.
You need to use the dotted notation in the field names used for $set
See https://docs.mongodb.org/manual/tutorial/modify-documents/
I have this data in my text file.
Obj1= {
"AA" : "sasa",
"BB" : "fdsfsf",
"CC" : "sfsdf",
"DD" : "kmdksmd",
"EE" : "dsnjsdn"
};
Obj2= {
"DD" : "ndjsdnsjd",
"MM" : "jskdjskadn"
};
This data is in a single text file. How do I convert this to two different objects in JAVA
Is it possible to use more friendly, fully JSON format instead? It might look like:
{
"Obj1" : {
"AA" : "sasa",
"BB" : "fdsfsf",
"CC" : "sfsdf",
"DD" : "kmdksmd",
"EE" : "dsnjsdn"
},
"Obj2" : {
"DD" : "ndjsdnsjd",
"MM" : "jskdjskadn"
}
}
Then it would be very easy to load it like described in this thread
The file from your example isn't the correct JSON file so you can't do that so easily. If you really want to stick with your format, you would have to somehow tokenize/parse the file first to extract valid JSON fragments and than pass it to e.g. GSON library to convert them to objects.
If these will be small files like from your example, you can just load the whole file to string and try use regular expressions (with groups) and/or StringTokenizer to extract JSON chunks.
{
"Employee": [
{
"empMID": "mock:1",
"comments": [],
"col1": "something",
"contact": [{"address":"2400 waterview", "freetext":true}
],
"gender": "male"
},
{
"empMID": "mock:2",
"comments": [],
"col1": "something",
"contact": [{"address":"2200 waterview", "freetext":true}
],
"gender": "female"
}
],
"cola": false,
"colb": false
}
This is how my Json file looks .I m required to convert this json to a csv .(I m trying to convert a multi-dimesional data to 2d).I m using gson for my purpose.I cannot use gson.fromgson() function to object map with a template because it should be generic .
I know we can use CDL to convert jsonarray to csv format but It wont work in my case .
my csv format looks like
Employee*
empMID,comment.$,contact.address,contact.freetext,gender
mock:1,,2400 waterview,TRUE,male
mock:123,,2200 waterview,TRUE,female
colA#
TRUE
colB#
FALSE
I tried using google-GSON api to convert to this format .But I m not able to convert to this format .I have used * to represent its a json array and # to represent its a primitive type and contact.address to represent nested array inside another json array .I having problem relating this nested structure .I m able to traverse everything recursively like a column. Thanks in advance
public static void main(String[] args) throws IOException{
BufferedReader reader=null;
StringBuilder content=null;
String result=null;
reader = new BufferedReader(new FileReader("temp.json"));
String line = null;
content= new StringBuilder();
while ((line = reader.readLine()) != null) {
content.append(line);
}
reader.close();
result= content.toString();
JsonElement jelement = new JsonParser().parse(result);
printJsonRecursive(jelement);
}
public static void printJsonRecursive(JsonElement jelement){
if(jelement.isJsonPrimitive()){
System.out.println(jelement.getAsString());
return;
}
if(jelement.isJsonArray()){
JsonArray jarray= jelement.getAsJsonArray();
for(int i=0;i<jarray.size();i++){
JsonElement element= jarray.get(i);
printJsonRecursive(element);
}
return;
}
JsonObject jobject= jelement.getAsJsonObject();
Set<Entry<String, JsonElement>> set= jobject.entrySet();
for (Entry<String, JsonElement> s : set) {
printJsonRecursive(s.getValue());
}
}
}
You can achieve this thru reflection if you have a object mapped to the json.
use gson/jackson to convert json to java object
append fields using reflection by iterating the class and get any field you interested in.
append value with reflection by getting value from the target object.
More detail look at my blog post below:
vcfvct.wordpress.com/2015/06/30/converting-nested-json-files-to-csv-in-java-with-reflection/
You are not printing the key. This should fix it.
for (Entry<String, JsonElement> s : set) {
System.out.println(s.getKey()); //Added
printJsonRecursive(s.getValue());
}
You can take care of \ns from here.
EDIT
If you want to print the keys just once for repeating json objects, create a Java bean to hold the data and populate it during your recursion. Once the bean is complete, add a method there to print all the data in the format you want (printing keys only once and so on).
You can use the library json2flat for converting your JSON to CSV.
This library doesn't require any POJO's. It simply takes your JSON as string and returns a 2D representation of it in the format of List<Object[]>.
For example for the JSON:
{
"Employee": [
{
"empMID": "mock:1",
"comments": [],
"col1": "something",
"contact": [{"address":"2400 waterview", "freetext":true}
],
"gender": "male"
},
{
"empMID": "mock:2",
"comments": [],
"col1": "something",
"contact": [{"address":"2200 waterview", "freetext":true}
],
"gender": "female"
}
],
"cola": false,
"colb": false
}
It gives an output:
/cola,/colb,/Employee/empMID,/Employee/col1,/Employee/gender,/Employee/contact/address,/Employee/contact/freetext
,,"mock:1","something",,"2400 waterview",true
,,"mock:2","something",,"2200 waterview",true
false,false,,,,,
/**
* Get separated comlumns used a separator (comma, semi column, tab).
*
* #param headers The CSV headers
* #param map Map of key-value pairs contains the header and the value
*
* #return a string composed of columns separated by a specific separator.
*/
private static String getSeperatedColumns(Set<String> headers, Map<String, String> map, String separator) {
List<String> items = new ArrayList<String>();
for (String header : headers) {
String value = map.get(header) == null ? "" : map.get(header).replaceAll("[\\,\\;\\r\\n\\t\\s]+", " ");
items.add(value);
}
return StringUtils.join(items.toArray(), separator);
}