1. Обзор
В этом кратком руководстве мы покажем, как проверить сериализуемый объект в Java .
2. Сериализация и десериализация
Сериализация — это процесс преобразования состояния объекта в поток байтов . Сериализованные объекты в основном используются в технологиях Hibernate, RMI, JPA, EJB и JMS.
Переключая направления, десериализация — это обратный процесс, в котором поток байтов используется для воссоздания фактического объекта Java в памяти. Этот процесс часто используется для сохранения объекта .
3. Проверка сериализации
Мы можем проверить сериализацию, используя различные методы. Давайте посмотрим на некоторые из них.
3.1. Проверка реализует
сериализацию
Самый простой способ определить, является ли объект сериализуемым, — это проверить, является ли этот объект экземпляром java.io.Serializable
или java.io.Externalizable
. Однако этот метод не гарантирует, что мы сможем сериализовать объект.
Допустим, у нас есть объект Address
, который не реализует интерфейс Serializable :
public class Address {
private int houseNumber;
//getters and setters
}
При попытке сериализовать объект Address может возникнуть
исключение NotSerializableException
:
@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);
}
}
Теперь предположим, что у нас есть объект Person
, который реализует интерфейс Serializable :
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private int age;
private String name;
// getters and setters
}
В этом случае мы сможем сериализовать и десериализовать, чтобы воссоздать объект обратно:
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
Другой способ проверить сериализацию объекта — использовать метод сериализации
из Apache Commons SerializationUtils
. Этот метод не примет несериализуемый объект.
Что, если мы попытаемся сериализовать несериализуемый объект Address
, явно приведя тип для компиляции кода? Во время выполнения
мы столкнемся с ClassCastException
:
Address address = new Address();
address.setHouseNumber(10);
SerializationUtils.serialize((Serializable) address);
Давайте используем приведенное выше для проверки сериализуемого объекта Person :
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
Теперь мы рассмотрим метод SerializationUtils
из spring-core , который похож на метод из Apache Commons. Этот метод также не принимает несериализуемый объект Address .
Такой код вызовет исключение ClassCastException
во время выполнения:
Address address = new Address();
address.setHouseNumber(10);
org.springframework.util.SerializationUtils.serialize((Serializable) address);
Давайте попробуем с сериализуемым объектом Person :
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. Пользовательская утилита сериализации
В качестве третьего варианта мы создадим собственную пользовательскую утилиту для сериализации или десериализации в соответствии с нашими требованиями. Чтобы продемонстрировать это, мы напишем два отдельных метода для сериализации и десериализации.
Первый пример проверки объекта для процесса сериализации:
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();
}
Мы также напишем метод для выполнения процесса десериализации:
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);
}
Кроме того, мы можем создать служебный метод, который принимает Class
в качестве параметра и возвращает true
, если объект сериализуем. Этот метод предполагает, что примитивы и интерфейсы неявно сериализуемы при проверке, может ли входной класс быть присвоен Serializable
или нет. Кроме того, мы исключаем временные
и статические
поля в процессе проверки.
Давайте реализуем этот метод:
public static boolean isSerializable(Class<?> it) {
boolean serializable = it.isPrimitive() || it.isInterface() || Serializable.class.isAssignableFrom(it);
if (!serializable) {
return false;
}
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();
if (!isSerializable(fieldType)) {
return false;
}
}
return true;
}
Давайте теперь проверим наш служебный метод:
assertFalse(MySerializationUtils.isSerializable(Address.class));
assertTrue(MySerializationUtils.isSerializable(Person.class));
assertTrue(MySerializationUtils.isSerializable(Integer.class));
4. Вывод
В этой статье мы рассмотрели несколько способов определить, является ли объект сериализуемым или нет. Мы также продемонстрировали пользовательскую реализацию для достижения того же.
Как обычно, все примеры кода, используемые в этом руководстве, доступны на GitHub .