Skip to content

Best_Practice_en

رامي مناف edited this page Aug 27, 2020 · 4 revisions

Best Practice

Rules to Save Data Safely

These rules will facilitate your usage to the database and it's very important to follow them in writing any new class.

  • It's preferred to use JavaBeans rules in writing your class.
  • If you have a field you don't want to save it write the keyword transient before it only if you didn't define the way that the object data should be written.
  • Use a good structure for your classes to prevent writing the same code many times.
  • Write all the operations you will need it in methods.
  • It's preferred to define the way that your object data should be written (explained later in this page);
  • Always implement the equals method because many commands depend on it.

There is three serializers in sofof. The default serializer is sofof serializer. This serializer saves fields names and values so you can add and remove fields freely. If you decided to use this serializer you have to write a default constructor with no arguments. Sofof serializer also use java serialization API to serialize classes that implements Serializable interface. It's very recommended to use this serializer. Sofof also offers java serializer which is implemented with java serialization api. That will let you use many features from that API. The serializing starts with the checking of that the class or one of its parents implements the Serializable interface. Then it will write all the fields that aren't final, transient or static. That was the default implementation to the serializing mechanism of any class but you can edit it to have your own serializing mechanism (preferred always). You can implement it for your class by writing the mechanism in void writeObject(ObjectOutputStream) method. Using the method parameter ObjectOutputStream you can write your fields in a certain order by passing each of them to the suitable method of the ObjectOutputStream parameter like writeInt, writeLong, writeUTF, writeObject. The writeObject method is used to serialize the class objects but you have to write the opposite mechanism to read the class fields in the same order in the void readObject(ObjectInputStream).

If you didn't implement the reading and writing mechanisms you couldn't read the old serialized objects after editing the class (even if you have just written a new method and didn't edit the fields) and that will throw an exception. So, it's very important to implement your mechanism for any class you want to save it in sofof.

When you use the default mechanism or your mechanism in reading the object the constructor won't be called before creating the new instance that you have. So, it's important to know that all your default field values that are written in the constructor will not be applied to your fields. This example will show you an ideal class that follows the previous rules:

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Objects;

public class Student implements Serializable {

    private static final long serialVersionUID = 4702347432L;
    
    private String name;
    private int age;
    private String nationality;
    
    public Student(String name, int age, String nationality){
        this.nationality = nationality;
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public String getNationality() {
        return nationality;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setNationality(String nationality) {
        this.nationality = nationality;
    }

    

    private void readObject(ObjectInputStream in) throws IOException {
        name = in.readUTF();
        age = in.readInt();
        nationality = in.readUTF();
    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        out.writeUTF(name);
        out.writeInt(age);
        out.writeUTF(nationality);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Student other = (Student) obj;
        if (!Objects.equals(this.name, other.name)) {
            return false;
        }
        if (!Objects.equals(this.age, other.age)) {
            return false;
        }
        if (!Objects.equals(this.nationality, other.nationality)) {
            return false;
        }
        return true;
    }

}

The third serializer is json serializer. You can use this to serialize objects to json. This serializer can serialize simple objects that can be written as a json only.

Tricks for java serializer

You can do some tricks to avoid problems that you will face in the future when using Sofof. Those are some of them:

Saving Fields That Don't Implement The Serializable Interface

When you try to build complex classes probably you will face some fields that don't implement the Serializable interface. You can solve that problem by implementing the mechanism of reading and writing the class objects and try to write the serializable core data of that field and then read it to use it to build the unserializable class object. For example: when you want to use a JavaFX Property field like SimpleStringProperty which doesn't implement the Serializable interface you can write a code similar to the following:

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import javafx.beans.property.SimpleStringProperty;

public class Person implements Serializable {

    private static final long serialVersionUID = 8036435743L;
    
    private SimpleStringProperty name;

   public Person(){
      name = new SimpleStringProperty(this, "name", "");
   }
   
   private void writeObject(ObjectOutputStream out) throws IOException {
        out.writeUTF(name.getValue());
    }
          
     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        this.name = new SimpleStringProperty(this, "name", in.readUTF());
    }

}

Editing The Class Fields

After deploying your project and you want to do an update you may want to add or remove a field. This process will make the old serialized objects invalid to the new class. You can avoid that if you implemented the mechanism of writing/reading the class objects from the beginning. This trick requires a good understanding of the reading/writing mechanism of the object data. If you want to remove some fields in the class don't remove the line that read them in the implementation of the reading mechanism but doesn't assign it's value to any variable and pass a default value to the writing mechanism (such as null, 0). If you want to add a new field write it after writing all the old fields and surround it's reading code line with a try-catch(EOFException). That because when you try to read the old serialized objects the reading of the new field will throw an EOFException telling you that this is the end of the data (the new field value doesn't exist in the old object data). The previous tricks are applicable in the projects that you don't want to write update code to the database (e.g: desktop applications). If you have a database for your website or you want to write un update code to your desktop software it's preferred to do other mechanisms to update all the objects at one time. This is an example of the previous trick:

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class User implements Serializable {

    private static final long serialVersionUID = 555646L;
    
    private String username;
    private String password;
    private String image;

    private void readObject(ObjectInputStream in) throws IOException {
        username = in.readUTF();
        password = in.readUTF();
        image = in.readUTF();
    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        out.writeUTF(username);
        out.writeUTF(password);
        out.writeUTF(image);
    }
}

This is the class after removing the image field and adding the nickname field:

import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class User implements Serializable {

    private static final long serialVersionUID = 555646L;
    
    private String username;
    private String nickname;
    private String password;

    private void readObject(ObjectInputStream in) throws IOException {
        username = in.readUTF();
        password = in.readUTF();
        in.readUTF();
        try{
        nickname = in.readUTF();
        }catch(EOFException ex){}
    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        out.writeUTF(username);
        out.writeUTF(password);
        out.writeUTF(null);
        out.writeUTF(nickname);
    }
}

Clone this wiki locally