Java как запретить сериализацию класса

How to lock serialization in Java?

I am just starting with Java serialization: I have one exercise to do and I need to lock serialization on any class, it is suppose to throw an exception when I attempt to serialize that class. Does anyone know how to do it?

4 Answers 4

If you add an implementation of writeObject which throws an exception, serialization will be aborted, e.g.

 private void writeObject(ObjectOutputStream stream) throws IOException

See http://java.sun.com/developer/technicalArticles/ALT/serialization/ for a good introduction to overriding the default serialization behaviour.

I would recommend throwing a more specific UnsupportedOperationException instead of the general RuntimeException .

The three custom serialisation methods you want to provide are writeObject , readObject and readObjectNoData . The appropriate exception to throw is the appropriately named java.io.NotSerializableException .

private void writeObject( ObjectOutputStream out < ) throws IOException < throw new NotSerializableException(); >private void readObject( ObjectInputStream in ) throws IOException, ClassNotFoundException < throw new NotSerializableException(); >private void readObjectNoData( ) throws ObjectStreamException

A little trick (though not actually specified in the spec) is to cause an NPE when the system attempts to create the matching java.io.ObjectStreamClass . I

private static final ObjectStreamField[] serialPersistentFields =

Источник

Сериализация

Сериализация (Serialization) — процесс преобразования структуры данных в линейную последовательность байтов для дальнейшей передачи или сохранения.

Сериализованные объекты можно затем восстановить (десериализовать).

В Java, согласно спецификации Java Object Serialization существует два стандартных способа сериализации: стандартная сериализация, через использование интерфейса java.io.Serializable и «расширенная» сериализация — java.io.Externalizable.

Сериализация позволяет в определенных пределах изменять класс.

Вот наиболее важные изменения, с которыми спецификация Java Object Serialization может справляться автоматически:

  • добавление в класс новых полей;
  • изменение полей из статических в нестатические;
  • изменение полей из транзитных в нетранзитные.

Обратные изменения (из нестатических полей в статические и из нетранзитных в транзитные) или удаление полей требуют определенной дополнительной обработки в зависимости от того, какая степень обратной совместимости необходима.

Сериализация работает быстрее, чем JSON и XML, за счет того что это бинарные данные (байты).

Для чего нужна сериализация?

для передачи или сохранения объектов (данных).

Процесс сериализации/десериализации с использованием Serializable

При использовании Serializable применяется алгоритм сериализации, который с помощью рефлексии (Reflection API) выполняет:

  • запись в поток метаданных о классе, ассоциированном с объектом (имя класса, идентификатор SerialVersionUID, идентификаторы полей класса);
  • рекурсивную запись в поток описания суперклассов (загоняются все классы по очереди) до класса java.lang.Object (не включительно);
  • запись примитивных значений полей сериализуемого экземпляра, начиная с полей самого верхнего суперкласса;
  • рекурсивную запись объектов, которые являются полями сериализуемого объекта.
Читайте также:  Kotlin json to byte array

Рефлексия (от позднелат. reflexio — обращение назад) — это механизм исследования данных о программе во время её выполнения.

Рефлексия позволяет исследовать информацию о полях, методах и конструкторах классов.

При этом ранее сериализованные объекты повторно не сериализуются, что позволяет алгоритму корректно работать с циклическими ссылками.

Для выполнения десериализации под объект выделяется память, после чего его поля заполняются значениями из потока. Конструктор объекта при этом не вызывается.

Однако при десериализации будет вызван конструктор без параметров родительского несериализуемого класса, а его отсутствие повлечет ошибку десериализации.

Для сериализации объектов в поток используется класс ObjectOutputStream.

void writeObject(Object obj) — записывает в поток отдельный объект

void close() — закрывает поток

void flush() — очищает буфер и сбрасывает его содержимое в выходной поток

Для десериализации – ObjectInputStream.

Object readObject() считывает из потока объект

void close() — закрывает поток

Изменение и настройка сериализации

Как изменить стандартное поведение сериализации/десериализации?

Реализовать интерфейс java.io.Externalizable, который позволяет применение пользовательской логики сериализации.

Способ сериализации и десериализации описывается в методах writeExternal() и readExternal().

Во время десериализации вызывается конструктор без параметров, а потом уже на созданном объекте вызывается метод readExternal.

Для «мегакастомной» сериализации. Не пишется мета-информация и инфа о суперклассах.

Если у сериализуемого объекта реализован один из следующих методов, то механизм сериализации будет использовать его, а не метод по умолчанию :

writeObject() — запись объекта в поток

readObject() — чтение объекта из потока

writeReplace() — позволяет заменить себя экземпляром другого класса перед записью

readResolve() — озволяет заменить на себя другой объект после чтения

Будет ли сериализовано final поле?

Какие поля не будут сериализованы при сериализации?

Поля класса, помеченные модификатором transient , не сериализуются.

Обычно в таких полях хранится промежуточное состояние объекта, которое, к примеру, проще вычислить. Другой пример такого поля — ссылка на экземпляр объекта, который не требует сериализации или не может быть сериализован.

При стандартной сериализации поля, имеющие модификатор static , не сериализуются.

Соответственно, после десериализации это поле значения не меняет.

При использовании реализации Externalizable сериализовать и десериализовать статическое поле можно, но не рекомендуется этого делать, т.к. это может сопровождаться трудноуловимыми ошибками.

Поля с модификатором final сериализуются как и обычные.

За одним исключением – их невозможно десериализовать при использовании Externalizable, поскольку final поля должны быть инициализированы в конструкторе, а после этого в readExternal() изменить значение этого поля будет невозможно. Соответственно, если необходимо сериализовать объект с final полем необходимо использовать только стандартную сериализацию.

Читайте также:  K nearest neighbors python example

Как создать собственный протокол сериализации?

Для создания собственного протокола сериализации достаточно реализовать интерфейс Externalizable, который содержит два метода:

public void writeExternal(ObjectOutput out) throws IOException;

public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException

Какая роль поля serialVersionUID в сериализации?

serialVersionUID используется для указании версии сериализованных данных.

Когда мы не объявляем serialVersionUID в нашем классе явно, среда выполнения Java делает это за нас, но этот процесс чувствителен ко многим метаданным класса включая количество полей, тип полей, модификаторы доступа полей, интерфейсов, которые реализованы в классе и пр.

Рекомендуется явно объявлять serialVersionUID т.к. при добавлении, удалении атрибутов класса динамически сгенерированное значение может измениться и в момент выполнения будет выброшено исключение InvalidClassException.

private static final long serialVersionUID = 20161013L;

Когда стоит изменять значение поля serialVersionUID?

serialVersionUID нужно изменять при внесении в класс несовместимых изменений, например при удалении какого-либо его атрибута.

Как не допустить сериализацию

Чтобы не допустить автоматическую сериализацию можно переопределить private методы для создания исключительной ситуации NotSerializableException.

private void writeObject(ObjectOutputStream out) throws IOException

throw new NotSerializableException();

private void readObject(ObjectInputStream in) throws IOException

throw new NotSerializableException();

Любая попытка записать или прочитать этот объект теперь приведет к возникновению исключительной ситуации.

В чем проблема сериализации Singleton?

Проблема в том, что после десериализации мы получим другой объект. Таким образом, сериализация дает возможность создать Singleton еще раз, что недопустимо.

Существует два способа избежать этого:

  • явный запрет сериализации
  • определение метода с сигнатурой default/public/private/protected Object readResolve() throws ObjectStreamException назначением которого станет возврат замещающего объекта вместо объекта, на котором он вызван.

Клонирование объектов

3 СПОСОБА

Какой способ клонирования предпочтительней?

Наиболее безопасным и следовательно предпочтительным способом клонирования является использование специализированного конструктора копирования:

  • Отсутствие ошибок наследования (не нужно беспокоиться, что у наследников появятся новые поля, которые не будут склонированы через метод clone());
  • Поля для клонирования указываются явно;
  • Возможность клонировать даже final поля.

Почему метод clone() объявлен в классе Object, а не в интерфейсе Cloneable?

Метод clone() объявлен в классе Object с указанием модификатора native , чтобы обеспечить доступ к стандартному механизму поверхностного копирования объектов.

Одновременно он объявлен и как protected , чтобы нельзя было вызвать этот метод у не переопределивших его объектов.

Непосредственно интерфейс Cloneable является маркерным (не содержит объявлений методов) и нужен только для обозначения самого факта, что данный объект готов к тому, чтобы быть клонированным.

Вызов переопределённого метода clone() у не Cloneable объекта вызовет выбрасывание CloneNotSupportedException.

Как создать глубокую копию объекта?

Источник

java Сериализация

Добрый день. Изучаем сериализацию. В данном случае, надо поставить запрет сериализации. Так вот, почему если поставить у SubSolution.writeObject модификатор доступа public, то сериализация пройдет ? Что-то не могу понять. Буду благодарен за ссылку на похожий вопрос или статью/литературу.

public class TestFile implements Serializable < public static void main(String args[]) throws Exception < FileOutputStream fileOutput = new FileOutputStream("FilePath"); ObjectOutputStream outputStream = new ObjectOutputStream(fileOutput); SubSolution subSolution = new SubSolution(); outputStream.writeObject(subSolution); fileOutput.close(); outputStream.close(); >public static class SubSolution extends TestFile < private void writeObject(ObjectOutputStream objectOutput) throws Exception < throw new NotSerializableException(); >private void readObject(ObjectInputStream objectInput) throws Exception < throw new NotSerializableException(); >> > 

Но теоретически, мы наследуемся от класса, у которого разрешена сериализация, а вот в подклассе она должна быть запрещена.

Читайте также:  Php сделать отрицательное число

1 ответ 1

В документации на Serializable написано:

Классы, требующие специальной обработки в процессе сериализации и десериализации должны реализовывать специальные методы с в точности такими сигнатурами:

 private void writeObject(java.io.ObjectOutputStream out) throws IOException private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException; private void readObjectNoData() throws ObjectStreamException; 

Данные методы вызываются через reflection, соответствующие объекты Method заполняются с учетом требований выше. При замене private на public метод не считается подходящим и игнорируется.

Источник

Как заблокировать сериализацию в Java?

Я только начинаю сериализацию Java: у меня есть одно упражнение, и мне нужно заблокировать сериализацию для любого класса, предполагается, что при попытке сериализации этого класса возникает исключение.

кто нибудь знает как это сделать?

4 ответа

Если вы добавите реализацию writeObject который выдает исключение, сериализация будет прервана, например

 private void writeObject(ObjectOutputStream stream) throws IOException

См. http://java.sun.com/developer/technicalArticles/ALT/serialization/ для хорошего введения в переопределение поведения сериализации по умолчанию.

Три пользовательских метода сериализации, которые вы хотите предоставить: writeObject , readObject а также readObjectNoData , Подходящее исключение для броска — с соответствующим именем java.io.NotSerializableException ,

private void writeObject( ObjectOutputStream out < ) throws IOException < throw new NotSerializableException(); >private void readObject( ObjectInputStream in ) throws IOException, ClassNotFoundException < throw new NotSerializableException(); >private void readObjectNoData( ) throws ObjectStreamException

Небольшая хитрость (хотя на самом деле это не указано в спецификации) — вызвать NPE, когда система пытается создать соответствующий java.io.ObjectStreamClass , Я null s.

private static final ObjectStreamField[] serialPersistentFields =

Классы, которые требуют специальной обработки в процессе сериализации и десериализации, должны реализовывать специальные методы с такими точными сигнатурами:

private void writeObject(java.io.ObjectOutputStream out) throws IOException private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException; 

Вы всегда можете попытаться перегрузить writeObject с подписью выше, и выбросить исключение.

Сериализация доступна только для классов, которые реализуют Serializable (прочитайте документы этого интерфейса). Я не думаю, что вы можете включить его во время выполнения. Если вы не хотите, чтобы объекты были сериализуемыми, не заставляйте их реализовывать Serializable ,

Если сериализация находится под вашим контролем (т.е. вы звоните ObjectOutputStream.writeObject(..) ), затем просто сделайте опцию конфигурации, которая запретит этот вызов.

Другим вариантом будет реализация writeObject(ObjectOutputStream out) метод и выбрасывать исключение в зависимости от параметра конфигурации.

Источник

Оцените статью