LS Price Increase Launch

The Price of all “Learn Spring” course packages will increase by $40 on next Friday:

>> GET ACCESS NOW

1. Overview

In this quick tutorial, we'll demonstrate how to validate a Serializable object in Java.

2. Serialization and Deserialization

Serialization is the process of converting the state of an object into a byte stream. Serialized objects are primarily used in Hibernate, RMI, JPA, EJB, and JMS technologies.

Switching directions, deserialization is the reverse process where the byte stream is used to recreate the actual Java object in memory. This process is often used to persist the object.

3. Serialization Validation

We can verify serialization using a variety of methods. Let's take a look at a few.

3.1. Validate implements Serialization

The simplest approach to determine whether an object is serializable is to check whether that object is an instance of java.io.Serializable or java.io.Externalizable. However, this method does not guarantee that we can serialize an object.

Let's say we have an Address object that doesn't implement the Serializable interface:

public class Address {
    private int houseNumber;

    //getters and setters
}

While attempting to serialize an Address object, a NotSerializableException might occur:

@Test(expected = NotSerializableException.class)
public void whenSerializing_ThenThrowsError() throws IOException {
    Address address = new Address();
    address.setHouseNumber(10);
    FileOutputStream fileOutputStream = new FileOutputStream("yofile.txt");
    try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream)) {
        objectOutputStream.writeObject(address);
    }
}

Now, let's say we have a Person object that implements the Serializable interface:

public class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    private int age;
    private String name;

    // getters and setters
}

In this case, we'll be able to serialize and deserialize to re-create the object back:

Person p = new Person();
p.setAge(20);
p.setName("Joe");
FileOutputStream fileOutputStream = new FileOutputStream("yofile.txt");
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream)) {
    objectOutputStream.writeObject(p);
}

FileInputStream fileInputStream = new FileInputStream("yofile.txt");
try ( ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) {
    Person p2 = (Person) objectInputStream.readObject();
    assertEquals(p2.getAge(), p.getAge());
    assertEquals(p2.getName(), p.getName());;
}

3.2. Apache Commons SerializationUtils

Another way to validate the serialization of an object is to utilize the serialize method from Apache Commons SerializationUtils. This method will not accept an object that is not serializable.

What if we try to serialize the non-serializable Address object by explicitly type-casting to compile the code? At runtime, we'll encounter a ClassCastException:

Address address = new Address();
address.setHouseNumber(10);
SerializationUtils.serialize((Serializable) address);

Let's use the above to validate the serializable Person object:

Person p = new Person();
p.setAge(20);
p.setName("Joe");
byte[] serialize = SerializationUtils.serialize(p);
Person p2 = (Person)SerializationUtils.deserialize(serialize);
assertEquals(p2.getAge(), p.getAge());
assertEquals(p2.getName(), p.getName());

3.3. Spring Core SerializationUtils

We'll now look at the SerializationUtils method from spring-core, which is similar to the method from Apache Commons. This method also does not accept the non-serializable Address object.

Such code will throw a ClassCastException at runtime:

Address address = new Address();
address.setHouseNumber(10);
org.springframework.util.SerializationUtils.serialize((Serializable) address);

Let's try with the serializable Person object:

Person p = new Person();
p.setAge(20);
p.setName("Joe");
byte[] serialize = org.springframework.util.SerializationUtils.serialize(p);
Person p2 = (Person)org.springframework.util.SerializationUtils.deserialize(serialize);
assertEquals(p2.getAge(), p.getAge());
assertEquals(p2.getName(), p.getName());

3.4. Custom Serialization Utility

As a third option, we'll create our own custom utility to serialize or deserialize according to our requirements. To demonstrate this, we'll write two separate methods for serialization and deserialization.

The first is an example of object validation for the serialization process:

public static  byte[] serialize(T obj) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(obj);
    oos.close();
    return baos.toByteArray();
}

We'll also write a method to perform the deserialization process:

public static  T deserialize(byte[] b, Class cl) throws IOException, ClassNotFoundException {
    ByteArrayInputStream bais = new ByteArrayInputStream(b);
    ObjectInputStream ois = new ObjectInputStream(bais);
    Object o = ois.readObject();
    return cl.cast(o);
}

Additionally, we can create a utility method that takes Class as a parameter and returns true if the object is serializable. This method would assume that the primitives and interfaces are implicitly serializable while validating if the input class can be assigned to Serializable or not. Also, we're excluding transient and static fields during the validation process.

Let's implement this method:

public static boolean isSerializable(Class<?> it) {
    boolean serializable = it.isPrimitive() || it.isInterface() || Serializable.class.isAssignableFrom(it);
    if (!serializable) {
        return serializable;
    }
    Field[] declaredFields = it.getDeclaredFields();
    for (Field field : declaredFields) {
        if (Modifier.isVolatile(field.getModifiers()) || Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {
            continue;
        }
        Class<?> fieldType = field.getType();
        return isSerializable(fieldType);
    }
    return serializable;
}

Let's now validate our utility method:

assertFalse(MySerializationUtils.isSerializable(Address.class));
assertTrue(MySerializationUtils.isSerializable(Person.class));
assertTrue(MySerializationUtils.isSerializable(Integer.class));

4. Conclusion

In this article, we looked at several ways to determine whether an object is serializable or not. We've also demonstrated a custom implementation to accomplish the same.

As is the custom, all the code samples used in this tutorial are available over on GitHub.

LS Price Increase Launch

The Price of all “Learn Spring” course packages will increase by $40 on next Friday:

>> GET ACCESS NOW
Generic footer banner
guest
0 Comments
Inline Feedbacks
View all comments