Android Read/Write JSON file to Internal Storage - java

I'm trying to use Gson to serialize my Java classes and store them in a .json file. I have an ArrayList<Foo> that I want to store under the node labeled Foo. Gson outputs something like this:
[{'id':1},{'id':2},{'id':3}]
I want the Json file to look like this:
{
'Foo': [{'id':1},{'id':2},{'id':3}],
'bar': ...
}
I've tried using the JsonWriter class, but I believe this is for external storage since I am getting a ReadOnly error. This is how I'm trying to write it:
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(gson.toJson(foos).getBytes()); // foos is ArrayList<Foo>
fos.close();
I'm thinking I need to store it in a JsonObject instead of writing it directly to a file. And instead of Jsonifying the entire ArrayList I could append each object individually. If I do this, how would I append it into the file (as opposed to the JsonObject)?
The main issue I'm facing is actually reading from the file. How do I go about reading the entire Json file into a JsonObject?

To get your desired output format, you could put your list in a Map with the key "foo."
Map<String, List<Foo>> map = new HashMap<>();
map.put("Foo", foos);
String output = gson.toJson(map);
Then you should get this output
{
'Foo': [{'id':1},{'id':2},{'id':3}]
}
Obviously the main reason you would want to do something like this is if you were storing things other than a list called 'Foo'.

Related

Add array to newly created file in Java

I'm passing an array of array to a java method and I need to add that data to a new file (which will be loaded into an s3 bucket)
How do I do this? I haven't been able to find an example of this
Also, I'm sure "object" is not the correct data type this attribute should be. Array doesn't seem to be the correct one.
Java method -
public void uploadStreamToS3Bucket(String[][] locations) {
try {
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withRegion(String.valueOf(awsRegion))
.build();
String fileName = connectionRequestRepository.findStream() +".json";
String bucketName = "downloadable-cases";
File locationData = new File(?????) // Convert locations attribute to a file and load it to putObject
s3Client.putObject(new PutObjectRequest(bucketName, fileName, locationData));
} catch (AmazonServiceException ex) {
System.out.println("Error: " + ex.getMessage());
}
}
You're trying to use PutObjectRequest(String,String,File)
but you don't have a file. So you can either:
Write your object to a file and then pass that file
or
Use the PutObjectRequest(String,String,InputStream,ObjectMetadata) version instead.
The later is better as you save the intermediate step.
As for how to write an object to a stream you may ask: Check this How can I convert an Object to Inputstream
Bear in mind to read it you have to use the same format.
It might be worth to think about what kind of format you want to save your information, because it might be needed to be read for another program, or maybe by another human directly from the bucket and there might be other formats / serializers that area easy to read (if you write JSON for instance) or more efficient (if you use another serializer that takes less space).
As for the type of array of array you can use the [][] syntax. For instance an array of array of Strings would be:
String [][] arrayOfStringArrays;
I hope this helps.

How can I convert JSON file into List of objects?

I'm trying to do a loader for my program and the saver into json works, but the reader doesn't. I'm basically converting my list of objects, let's say ArrayList ProjectArr into json which is working, now I'm gonna close terminal and load the info into my initially blank ProjectArr list so I can add the saved data loading feature. here is my reader :
public static ArrayList<Project> MapReaderforProject() {
ObjectMapper objectMapperforProject = new ObjectMapper();
String jsonfile = "C:/Users/elmm/Desktop/DS Project/DsProject/target/test1.json";
File file = new File("C:/Users/elmm/Desktop/DS Project/DsProject/target/test1.json");
try {
ProjectArr = objectMapperforProject.readValue(jsonfile,new TypeReference<ArrayList<Project>>(){});
}
catch (JsonMappingException e) {
} catch (JsonProcessingException e) {
}
System.out.println(ProjectArr.toString());
return ProjectArr;
}
But when I call this even though the JSON file is working and has the info, it's not reading anything and just prints [], empty list basically meaning it's not reading the data from JSON back into my list. Can someone please guide me?
There is some context information missing to give you more help. For example, what is ObjectMapper? Does it come from a library (and from which one) or have you written it yourself?
But what I have recognized so far: In line 3 you create a String which contains the file name. In line 4 you create a File object with the same file name. You could use the String there which you created the line above.
In line 6 you call the readValue method on the ObjectMapper instance and pass the String created in line 3, which contains the file name. Does this method really want a String there with the file name? If this is the ObjectMapper from the Jackson library, you need to parse the JSON code as the first parameter to the readValue call, not the file name.
So it looks like after line 4 you need code to read the content of the file which you should pass to the readValue method.
Check out this short tutorial: https://www.baeldung.com/jackson-object-mapper-tutorial
hth
McPringle

How to add append a new class object to the existing JSON file in Java?

I am trying to append a class object to the existing json file using java but getting following output:
[{"email_id":"anu55182#gmail.com","password":"Password
","user_name":"Anubhav Singh"}]
{"email_id":"madhav123#gmail.com","password":"madhav1234",
"user_name":"Madhav kumar"}
But the expected output should be:
[{"email_id":"anu55182#gmail.com", "password":"Password
","user_name":"Anubhav
Singh"},{"email_id":"madhav123#gmail.com","password":"madhav1234","user_name":"Madhav kumar"}]
My code:
FileWriter file = new FileWriter("/home/anubhav55182/NetBeansProjects/Tweetoria/src/java/Signup/data.json",Boolean.TRUE);//output json file
JSONObject obj = new JSONObject();//for json file generation
obj.put("user_name",name);
obj.put("user_id",username);
obj.put("email_id",email);
obj.put("password",pass);
file.write(obj.toJSONString());
file.flush();
Could someone help me to append new object to existing json file using java.
Thanks in advance for your help.
You're currently only adding another JSONObject to the file. The functionality you're looking for requires you to read in the existing file (with email_id: anu55182#gmail.com) as a JSONArray. From there, you can append the array with your new object.
You'll want to read in the file as an array, put the info to be added into a JSONObject (as you have above) and then add that object to the array.
Here are the Oracle docs for JSONArray: http://docs.oracle.com/javaee/7/api/javax/json/JsonArray.html

Write to Json using libGDX

I am new to Json and libGDX but I have created a simple game and I want to store player names and their scores in a Json file. Is there a way to do this? I want to create a Json file in Gdx.files.localStorage if it doesnt exist and if it does, append new data to it.
I have checked code given at :
1>Using Json.Serializable to parse Json files
2>Parsing Json in libGDX
But I failed to locate how to actually create a Json file and write multiple unique object values (name and score of each player) to it. Did I miss something from their codes?
This link mentions how to load an existing json but nothing else.
First of all i have to say that i never used the Libgdx Json API myself. But i try to help you out a bit.
I think this Tutorial on github should help you out a bit.
Basicly the Json API allows you to write a whole object to a Json object and then parse that to a String. To do that use:
PlayerScore score = new PlayerScore("Player1", 1537443); // The Highscore of the Player1
Json json = new Json();
String score = json.toJson(score);
This should then be something like:
{name: Player1, score: 1537443}
Instead of toJson() you can use prettyPrint(), which includes linebreaks and tabs.
To write this to a File use:
FileHandle file = Gdx.files.local("scores.json");
file.writeString(score, true); // True means append, false means overwrite.
You can also customize your Json by implementing Json.Serializable or by adding the values by hand, using writeValue.
Reading is similar:
FileHandle file = Gdx.files.local("scores.json");
String scores = file.readString();
Json json = new Json();
PlayerScore score = json.fromJson(PlayerScore.class, scores);
If you have been using a customized version by implementing Json.Serializable you have implemented the read (Json json, JsonValue jsonMap) method. If you implemented it correctly you the deserialization should work. If you have been adding the values by hand you need to create a JsonValuejsonFile = new JsonValue(scores). scores is the String of the File. Now you can cycle throught the childs of this JsonValue or get its childs by name.
One last thing: For highscores or things like that maybe the Libgdx Preferences are the better choice. Here you can read how to use them.
Hope i could help.

Creating and reading from a custom file type in Java

I'm creating an installer and there are some resource files (.xmls, .zip files, a .jar file, etc) that must be read during installation, but I'd like to pack them into a custom file (i.e., a .dat file) so that when distributed, users don't get to mess around with them too much. The problem is that the installer must be written in Java and I've never done this sort of thing before in any programming language. Is it even possible? If so, how can I pack it in a way that can be read by my Java app afterwards and how can I make my Java app read it?
There are a lot of questions you'll need to answer for yourself about the requirements of this filetype. Does it need to be compressed? Encrypted? Does it need to support random access reading, or is stream-reading good enough?
I could be wrong, but I don't think that's what you're asking in this question. If I'm reading you correctly, I think you're asking "how do I read & write arbitrary file data?"
So that's the question I'll answer. Update your question if that's not quite what you're looking for.
Custom filetypes can easily be implemented using the DataInputStream and DataOutputStream classes. These will let you read & write primitives (boolean, char, byte, int, long, float, double) to the stream. There are also some convenience methods for reading & writing UTF-8 encoded Strings, byte-arrays, and a few other goodies.
Let's get started.
For the sake of argument, let's pretend that all my data elements are byte arrays. And each of them has a name. So my filetype can be modeled logically as a Map<String, byte[]>. I'd implement my custom filetype reader/writer class like this:
public class MyFileTypeCodec {
public static void writeToFile(File f, Map<String, byte[]> map)
throws IOException {
// Create an output stream
DataOutputStream stream = new DataOutputStream(
new BufferedOutputStream(new FileOutputStream(f))
);
// Delegate writing to the stream to a separate method
writeToStream(stream, map);
// Always be sure to flush & close the stream.
stream.flush();
stream.close();
}
public static Map<String, byte[]> readFromFile(File f)
throws IOException {
// Create an input stream
DataInputStream stream = new DataInputStream(
new BufferedInputStream(new FileInputStream(f))
);
// Delegate reading from the stream to a separate method
Map<String, byte[]> map = readFromStream(stream);
// Always be sure to close the stream.
stream.close();
return map;
}
public static void writeToStream(DataOutputStream stream, Map<String, byte[]> map)
throws IOException {
// First, write the number of entries in the map.
stream.writeInt(map.size());
// Next, iterate through all the entries in the map
for (Map.Entry<String, byte[]> entry : map.entrySet()) {
// Write the name of this piece of data.
stream.writeUTF(entry.getKey());
// Write the data represented by this name, making sure to
// prefix the data with an integer representing its length.
byte[] data = entry.getValue();
stream.writeInt(data.length);
stream.write(data);
}
}
public static Map<String, byte[]> readFromStream(DataInputStream stream)
throws IOException {
// Create the data structure to contain the data from my custom file
Map<String, byte[]> map = new HashMap<String, byte[]>();
// Read the number of entries in this file
int entryCount = stream.readInt();
// Iterate through all the entries in the file, and add them to the map
for (int i = 0; i < entryCount; i++) {
// Read the name of this entry
String name = stream.readUTF();
// Read the data associated with this name, remembering that the
// data has an integer prefix representing the array length.
int dataLength = stream.readInt();
byte[] data = new byte[dataLength];
stream.read(data, 0, dataLength);
// Add this entry to the map
map.put(name, data);
}
return map;
}
}
The basic idea is that you can write any data to an output stream (and read it back again) if you can represent that data as some combination of primitives. Arrays (or other collections) can be prefixed with their length, like I've done here. Or you can avoid writing the length prefix if you put a TERMINUS sentinel at the end (kind of like null-terminated strings).
I always use this kind of setup when I implement a custom filetype codec, with file IO methods delegating down into stream IO methods. Usually, I discover later that the object I'm reading & writing from this stream could be just as easily written into some larger & more complex file.
So I might have a SuperFancyCodec for reading/writing the data for my whole system, and it calls down into my TinySpecialPurposeCodec. As long as the stream reading & writing methods are public, then I can assemble new filetypes using a component-oriented methodology.
The extension usually have very little to do with how the file is interpreted.
If you'd like to have just config.dat instead of config.xml you just rename the file. (You'd typically give an xml-parser an InputStream or a Reader as input, which may read any file, regardless of extension)
If the problem you're describing is about combining multiple files, (.zip, .jar, etc) into a single .dat file, you could for instance zip them together, and name the zip file with a .dat extension. Java has good support for zip-files and can handle the zip file regardless of filename / extension.
Related link: Reading the Contents of a ZIP File
When creating/reading files in Java (or anything else), the file extension is not strictly tyed to the actual structure of the file's data. If I wanted, I could make an XML files file.gweebz. OS's and applications would not know what to do with it, but once opened, it would be clear that it is XML.
That being said, it is often good to follow the conventions already established and usually .dat files are files in a binary format. You can use .dat for what you want, but be warned that some users may have OS bindings for the file type and clicking on your file may cause different-than-expected behavior on their systems.
As for how to do it in Java. Grabbing a file handle in Java is easy...
File myFile = new File("/dir/file.gweebz");
It is as simple as that and you can name it whatever you want. You will need other classes to write and read from the file or to do compression, but I will assume you know how to do that. If not, this site will have the answer.

Categories

Resources