I want a build an application, it's my first time so I have come up with a dilemma. In my application I have Persons and Projects and its one has its attributes. A project is done by some persons, and in each Project there is a Coordinator.
public class Person
{
private String firstName;
private String lastName;
private String mailAddress;
private String ID;
//more
}
also I have a Coordinator person:
public class Coordinator extends Person
{
private String type;
//more code
}
and then I have projects
public class Project
{
private String projectInfo;
private String nameOfProject;
private int projectID;
//more code
}
My dilemma is this. Should I store all the objects to a list or HasMap and then through object serialization to my disk or should I make an XML representation (like below) and then read my XML with a DOM parser? In XML way, everytime I will run the application, I will have to create my objects again, right? On the contrary with the serialization I will just read again my Objects from the disk.
<project>
<active></active>
<complete></complete>
<name></name>
<info></info>
<coordinator></coordinator>
<level1> //each project is distributed to different levels.
<cordinator> </cordinator>
<budget></budget>
<startDate></startDate>
<endDate></endDate>
<totalTasks> </totalTasks>
<complete></complete>
<task1>
<cordinator> </cordinator>
<personInvolved></personInvolved>
<personInvolved></personInvolved>
<personInvolved></personInvolved>
<personInvolved></personInvolved>
<budget></budget>
<startDate></startDate>
<endDate></endDate>
<complete></complete>
</task1>
<task2>
//same as task1
</task2>
</level1>
<level2>
//same as level1
</level2>
</project>
The choice between serializing using Java or XML doesn't depend on where you'd like to serialize it to. Both can be saved to a file. Java serialization dependent on the fact that every process reading the file is a Java program. (Nothing besides a Java program could read that format.) XML however is about interoperability. Any type of program can read an XML file and load in that data through some sort of library (JAXB or other non-Java XML serialization libraries).
Maintaining compatibility of serialized Java objects can be troublesome as the class changes, but it's not insurmountable. I don't try it though. If that were a factor for you, you might want to consider XML even if only Java programs were going to read it.
So the issue is -- who needs to read the data you're writing, and what are your needs for writing it in the first place?
I think the best way is the serialization, you can write down the object you want and easily read it:
Here an useful example
Here the official docs form Oracle
Serialize Person p:
try {
FileOutputStream fileOut = new FileOutputStream("/tmp/your_filename.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(p);
out.close();
fileOut.close();
}
catch(IOException i) {
// error management
}
Deserialize Person p:
try {
FileInputStream fileIn = new FileInputStream("/tmp/your_filename.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
p = (Person) in.readObject();
in.close();
fileIn.close();
}
catch(IOException i) {
// error management
}
catch(ClassNotFoundException c) {
// error management
}
Related
Is there a way to read a serialized object from a .ser file and update or delete one of the objects that have been serialized?
The following is my code which read's in objects of type 'Driver':
public boolean checkPassword(String userName, String password, String depot) throws IOException {
FileInputStream fileIn = new FileInputStream("Drivers.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
try
{
while (true) {
Driver d = (Driver) in.readObject();
if (d.userName.equals(userName) && d.password.equals(password) && d.depot.equals(depot))
{
this.isManager = d.isManager;
validAccount = true;
}
}
}
catch (Exception e) {}
return validAccount;
}
You will need to read all objects from the original file and then write a new file containing only the objects you want to retain or update.
The Java serialized object stream format is not an archive file format like ZIP, JAR, TAR and so on. It is just a sequence of serialized objects. There is no "index" that would facilitate updating or deleting objects.
This is one reason why serialized objects are not a good way to implement data persistence. This is what databases are designed for.
I am given an assignment where we are not allowed to use a DB or libraries but only textfile for data storage.
But it has rather complex requirements, for e.g. many validations, because of that, we need to "access the db" (i.e. read the textfile) many times.
My question is: should I create a class like this:
class SomeRepository{
static ArrayList<Users> users = new ArrayList();
public SomeRepository(){
//instantiate this class on program load
//In constructor, we read the text file, instantiate and store everything inside the arraylist.
}
//public getOneUser(){ // for get methods, we don't read from text file at all }
/public save() { //text file saving code overhere }
}
Is this a good approach to solve the above problem? Currently, what we are doing is reading and writing to the text file every time we want to retrieve some data or write something new.
Wouldn't this be too expensive in terms of heap space memory? Or should I just read/write to the text file for every method?
public class IOManager {
public static void writeObjToTxtFile(String fileName, Object object) {
File file = new File(fileName + ".txt");//File will be created in the root directory where the program runs.
try (FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);) {
oos.writeObject(object);
} catch (IOException e) {
e.printStackTrace();
}
}
public static Object readObjFromTxtFile(String fileName) {
Object obj = null;
File file = new File(fileName + ".txt");
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
obj = ois.readObject();
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return obj;
}
}
Add this class to your project. Since it's general for all Objects, you can pass and receive Objects like these as well: ArrayList<Users>. Play around and Tinker with it to fit whatever your specific purpose is. Hint: You can write other custom methods that calls these methods. eg:
public static void writeUsersToFile(ArrayList<Users> usersArrayList){
writeObjToTxtFile("users",usersArrayList);
}
Ps. Make sure your Objects implement Serializable. Eg:
public class Users implements Serializable {
}
I would suggest reading the contents of your file to a dynamic list such as an arraylist at the start of your program. Make the required queries/changes to your arraylist and then write that arraylist to your file when the program is set to close. This will save significant time over repeated file reads/writes.
This isn't without it's drawbacks, though. You don't want to hogg up memory in case of very large files - but considering this is an assignment, that may not be the case. Additionally, should your program terminate prior to the write at the end, all changes made to your database during the current execution will be lost.
I have a list of objects that has some simple String properties. I want to be able to save those strings to binary so that when you open the file outside the program, you only see 1's and 0's.
I have managed to use FileOutputStreamand saved the strings, however, I can't manage to get it to write to binary. The file reads as clean readable text. I have tried getBytes().
What would be the best approach for this? Keep in mind that I want to be able to read the file later and construct back the objects. Would it be better to use Serializable and save a list of objects?
Here is my FileWriter:
NB: The toString() is custom and returns a String with linebreaks for every property.
public class FileWriter {
public void write(String fileName, Savable objectToSave ) throws IOException {
File fileToSave = new File(fileName);
String stringToSave = objectToSave.toString();
byte[] bytesToSave = stringToSave.getBytes(StandardCharsets.UTF_8) ;
try (
OutputStream outputStream = new FileOutputStream(fileToSave);
) {
outputStream.write(bytesToSave);
} catch (IOException e) {
throw new IOException("error");
}
}
}
If your goal is simply serializing, implementing Serializable and writing them would work, but your string is still going to be readable. You can encrypt the stream, but anyone decompiling your code can still devise a way to read the values.
Before I proceed to my question : please note that I am not working on any client-server application that would require serialization, but the program I am trying to customize stores one big instance of one big class in a .dat file. I have read about this issue (memory leak in ObjectOutputStream and ObjectInputStream)and the fact that I could probably need to :
use the ObjectOutputStream.reset() method after writing the class instance in the .dat file, so that it doesn't hold the reference anymore;
re-write the code without using serialization;
split the file and read it in chunks;
change the JVM memory parameter by using -Xmx;
So, I was provided with one class that generates a language model and saves it with a .dat extension; the code was probably optimized for small model files (there are 2 model files provided as examples, both around 10MB ), but I generated a much larger model class, and it is around 40MB. Then, there is another class in another folder, totally independent on the first one, that uses this model, and the model has to be loaded using ObjectInputStream. Here comes the problem : a classic "OutOfMemoryError : Java heap space".
Writing the object:
try {
// Create an output stream to the file.
FileOutputStream file_output = new FileOutputStream (file);
ObjectOutputStream o = new ObjectOutputStream( file_output );
o.writeObject(this);
file_output.close ();
}
catch (IOException e) {
System.err.println ("IO exception = " + e );
}
Reading the object:
InputStream model = null;
ModelGeneration oRead = null;
ObjectInputStream p = null;
try {
model = new FileInputStream(filename);
BufferedInputStream buf = new BufferedInputStream(model);
p = new ObjectInputStream(buf);
oRead = (ModelGeneration) p.readObject();
p.reset();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
model.close();
} catch (Exception e) {
e.printStackTrace();
}
}
I tried to use the reset() method, but it is useless because we load only one instance of one class at a time, nothing else needed. This is why I can't split the file, too: only one class instance is stored in the .dat file.
Changing the heap space seems like a worse solution than optimizing the code.
I would really appreciate your advice on what I can do.
Btw the code is here : http://svn.apache.org/repos/asf/uima/addons/trunk/Tagger/, I only implemented the required classes for a different language.
P.S. Works fine if I create a smaller model, but I would prefer the bigger one.
For this specific project I need to serialize my entity layer (made of POJO's) to files. As I have the need for updating specific objects I would like to use one file per serialized object.
Example: Customer --ArrayList-> Order --ArrayList-> Product
When I edit a customer, and then serialize it using the java.io.Serializable interface, all fields, and their fields (please correct me if wrong), get serialized.
How would I apply serialization in such a way that only one object per file is used? I already have given each object a uniqe UUID which is used as filename when serializing.
If there are any frameworks that do File based ORM, that would be even better ;)
I'm not familiar with such framework.
What you can do is use other frameworks such as apache BeanUtils in order to perform the following recursive algorithm:
A. For each object gets its properties (assuming the object is a Java bean).
B. For each primitive field , write all primitives to file (you can use reflection to determine if a field is primitive or not).
C. For each non primitive file, write a special section in the file, pointing to the file name that will contain the object that is the value of the field.
D. Call recursively the algorithm for each non primitive field.
Similar approach can be done for collections -
HashMap, ArrayList and others.
The serializing code for the primitive elements can be the code provided by #Anshu
You can always read and write serializable objects using readObject and writeObject. Following is the example code:
import java.io.*;
import java.util.*;
import java.util.logging.*;
public class ExerciseSerializable {
public static void main(String... aArguments) {
//create a Serializable List
List<String> quarks = Arrays.asList(
"up", "down", "strange", "charm", "top", "bottom"
);
//serialize the List
//note the use of abstract base class references
try{
//use buffering
OutputStream file = new FileOutputStream( "quarks.ser" );
OutputStream buffer = new BufferedOutputStream( file );
ObjectOutput output = new ObjectOutputStream( buffer );
try{
output.writeObject(quarks);
}
finally{
output.close();
}
}
catch(IOException ex){
fLogger.log(Level.SEVERE, "Cannot perform output.", ex);
}
//deserialize the quarks.ser file
//note the use of abstract base class references
try{
//use buffering
InputStream file = new FileInputStream( "quarks.ser" );
InputStream buffer = new BufferedInputStream( file );
ObjectInput input = new ObjectInputStream ( buffer );
try{
//deserialize the List
List<String> recoveredQuarks = (List<String>)input.readObject();
//display its data
for(String quark: recoveredQuarks){
System.out.println("Recovered Quark: " + quark);
}
}
finally{
input.close();
}
}
catch(ClassNotFoundException ex){
fLogger.log(Level.SEVERE, "Cannot perform input. Class not found.", ex);
}
catch(IOException ex){
fLogger.log(Level.SEVERE, "Cannot perform input.", ex);
}
}
// PRIVATE //
//Use Java's logging facilities to record exceptions.
//The behavior of the logger can be configured through a
//text file, or programmatically through the logging API.
private static final Logger fLogger =
Logger.getLogger(ExerciseSerializable.class.getPackage().getName())
;
}