Если старый формат уже использует ObjectInputStream, входной поток нельзя считать доверенным. ObjectInputFilter ограничивает размер графа объектов и разрешает только классы, ожидаемые конкретным форматом.
Перечисляем допустимые типы явно:
private static final Set<Class<?>> ALLOWED =
Set.of(LegacyRecord.class, String.class);{}
В список включаются тип корневой записи и типы её полей, которые действительно сериализуются. Широкие разрешения для всех классов пакета превращают allowlist в формальность.
Сначала отсекаем слишком большие графы:
private static boolean tooLarge(
ObjectInputFilter.FilterInfo info) {
return info.depth() > 10
|| info.references() > 500
|| info.streamBytes() > 1_000_000;
}{}
Лимит глубины защищает от чрезмерно вложенных структур, а число ссылок ограничивает количество объектов. Дополнительно можно ограничить общий размер потока через info.streamBytes().
Проверяем тип каждого объекта отдельно:
private static boolean allowed(Class<?> type) {
return type == null || ALLOWED.contains(type);
}{}
Для служебных проверок фильтр может получить null вместо класса. Такой случай не означает, что неизвестный тип разрешён, поэтому решение о нём остаётся за статусом UNDECIDED.
Сначала отклоняем превышение лимитов и получаем тип:
private static ObjectInputFilter.Status filter(
ObjectInputFilter.FilterInfo info) {
if (tooLarge(info))
return ObjectInputFilter.Status.REJECTED;
Class<?> type = info.serialClass();{}
Затем разрешаем только перечисленные классы:
if (type == null)
return ObjectInputFilter.Status.UNDECIDED;
return allowed(type)
? ObjectInputFilter.Status.ALLOWED
: ObjectInputFilter.Status.REJECTED;{}
Эти проверки составляют тело фильтра. Превышение лимита отклоняется сразу, а неизвестный тип получает REJECTED, не проходя дальше по потоку.
Подключаем фильтр к потоку до десериализации:
input.setObjectInputFilter(MyFilters::filter);{}
Здесь MyFilters.filter объединяет проверки лимитов и типов из предыдущих шагов. Фильтр важно подключить до чтения, иначе объекты уже могут быть созданы.
После настройки получаем ожидаемый корневой объект:
LegacyRecord record = LegacyRecord.class
.cast(input.readObject());{}
👉 Java Ready | практика