deserialization issue

vm16
Новичок
Posts: 49
Joined: 07 Apr 2016 03:53

deserialization issue

Post by vm16 »

привет всем. может кто-то сталкивался подробно
пытаюсь сериализовать byte[] arr а потом десериализовать.
но возникает ощибка input stream header exception - вроде http://stackoverflow.com/questions/2163 ... r-00000000
может как-то вручную наладить внедрение magic values в stream ? типа - Object stream data is preceded by a 4 byte 'magical' sequence AC ED 00 05.
но надежно ли это ?

при попытке ObjectInputStream(BYtearrayinputStteam ) exception также
есть какие другие варианты ?
helg
Уже с Приветом
Posts: 4827
Joined: 15 May 2001 09:01

Re: deserialization issue

Post by helg »

vm16 wrote: 17 Mar 2017 16:48пытаюсь сериализовать byte[] arr а потом десериализовать.
"Сериализовать" объект в Java - это записать его в ObjectOutputStream, а не в то, что Вы написали.
vm16
Новичок
Posts: 49
Joined: 07 Apr 2016 03:53

Re: deserialization issue

Post by vm16 »

@helg - сорри спешил - неточно сформулировал.
на данный момент вопрос уперся в проблему
согласно http://iacquaint.blogspot.com/
в нижеприведенная функция вызывается два раза для объекта который содержит Date
но если используем упомянутый Bycicle (там внутири примитивы и нет поля типа Date) все работает - resolveClass вызывается один раз.
вопрос - почему для объекта который содержит Date resolve Class вызывается два раза ? неужели Date не сериализуется обычными средствами ?

--------- функция
@Override
protected Class resolveClass(ObjectStreamClass desc) throws IOException,
ClassNotFoundException {
if (!desc.getName().equals(Bicycle.class.getName())) {
throw new InvalidClassException(
"Unauthorized deserialization attempt",
desc.getName());
}
return super.resolveClass(desc);
}
helg
Уже с Приветом
Posts: 4827
Joined: 15 May 2001 09:01

Re: deserialization issue

Post by helg »

Вы бы программку небольшую, которая не работает, показали. Ну или задачу сформулировали бы. То, что по Вашей последней ссылке - неудачная попытка "быстро, на коленке" заткнуть дыру в безопасности, порождённую Object[In|Out]putStream.

Если Вам необходимо передать данные между двумя явами, не надо использовать означенные потоки объектов. Раньше стандартом было использование обычных потоков данных через сокеты, которые упаковывались-распаковывались в форматах специфичных для протокола обмена. Сейчас сервера раздают данные через http REST сервисы с использованием какой имплементации javax.ws.rs.
vm16
Новичок
Posts: 49
Joined: 07 Apr 2016 03:53

Re: deserialization issue

Post by vm16 »

привет всем !

вот собственно программа
проблема в том что при десериализации объекта OurClass функция resolveClass вызывается два раза.
в процессе объект как бы делится на две части. при трассировке - первая часть имеет тип OurClass
а вторая java,util.Date и соответственно resolveClass выбрасывает исключение, я подозреваю что причина этого - сушествует какой то нюанс десериализации Date
потому что например если убрать поля Date из OurClass все работает нормально. resolveClass вызывается только один раз
и обект десериализуется.

--------------------- код

public class OurClass implements Serializable {
private static final long serialVersionUID = 4543741824948041711L;

private int keyId_;
private String keyName_;
private String keyPassphrase_;
private Timestamp createdDate_;
private String key_;
private Date startDate_;
private Date endDate_;

}


class PGPObjectInputStream extends ObjectInputStream {

public PGPObjectInputStream(InputStream inputStream)
throws IOException {
super(inputStream);
}

@Override
protected Class resolveClass(ObjectStreamClass desc) throws IOException,
ClassNotFoundException {

if (desc.getName().equals(OurClass.class.getName())) {
return super.resolveClass(desc);
} else {
throw new InvalidClassException(
"Unauthorized deserialization attempt", desc.getName());

}
}
}


@RestController
@RequestMapping(value = URI)
public class LoginController {





@Loggable()
@RequestMapping(value = URI, method = RequestMethod.GET)
public Result getSomething(@PathVariable(parameter ) String userId,
HttpServletRequest request) throws Exception{



byte[] arr = new String("asdasdsad ads sda dsa das ads ").getBytes();
Date d1 = new Date("08/03/2013");
Date d2 = new Date("01/12/2011");
OurClass karr = new OurClass (999,"key111","key222","key345",d1,d2);



ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(karr);
byte[] buffer = baos.toByteArray();
oos.close();
baos.close();


ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
ObjectInputStream ois = new PGPObjectInputStream(bais);
OurClass temp = (OurClass ois.readObject();
ois.close();
bais.close();


System.out.println(" karr.keyid " + karr.getKeyId());
System.out.println(" karr.getKeyName " + karr.getKeyName());
System.out.println(" karr.getPassphrase " + karr.getPassphrase());
System.out.println(" karr.getCreatedDate " + karr.getCreatedDate());
System.out.println(" karr.getStartDate " + karr.getStartDate());
System.out.println(" karr.getEndDate " + karr.getEndDate());

System.out.println(" temp.keyid " + temp.getKeyId());
System.out.println(" temp.getKeyName " + temp.getKeyName());
System.out.println(" temp.getPassphrase " + temp.getPassphrase());
System.out.println(" temp.getCreatedDate " + temp.getCreatedDate());
System.out.println(" temp.getStartDate " + temp.getStartDate());
System.out.println(" temp.getEndDate " + temp.getEndDate());


try { do something
}
catch (Exception ex) {
ex.printStackTrace();
return something
}

return new result from controller
}


}
helg
Уже с Приветом
Posts: 4827
Joined: 15 May 2001 09:01

Re: deserialization issue

Post by helg »

Перед тем, как залезать в дебри кода, давайте решим вопрос по архитектуре.

Вы отдаёте данные в обёртке HTTP: RequestMapping в коде стоит, полагаю, из-за этого. HTTP по определению платформенно-независимый. Отдаёте Вы простой набор полей int/String/Date, который тоже платформенно-независимый. Но вместо того, чтобы отдавать набор в платформенно-независимом контейнере типа JSON или XML, Вы его отдаёте в Java-specific формате ObjectOutputStream. Принимать этот формат - прямая хирургия мозгов JVM. Чтобы в нём принимать данные надо быть абсолютно уверенным в чистых руках выдающего данные в этом формате. Судя по тому, что на входе десериализатора стоит простая проверка в resolveClass, уверенности в чистоте рук таки нет.

Я бы предложил сменить формат обмена c бинарного ObjectOutputStream на текстовый JSON. При этом наблюдаемая проблема уйдёт совсем. Вместе с ней уйдут проблемы "грязных рук" и прочий бардак с бинарной несовместимостью. Давайте так сделаем? Ну или расскажите: есть ли причины держать бинарный формат обмена.
vm16
Новичок
Posts: 49
Joined: 07 Apr 2016 03:53

Re: deserialization issue

Post by vm16 »

сорри что возможно ввел в заблуждение показал контроллер с requestmapping. единственная причина почему так делаю - для отладки. ну тупо после того как томкат поднимется дергаю веб сервис и смотрю результат. да и начальное приложение web. но вообще данные не передаются никуда по http.

----- между делом
если интересно там просто BLOB объект записан в базу. записан был после его сериализации в byte[]/ теперь его надо обратно десериализовать.
а изначально проблема была в том что контора требует соблюдение security а если не использовать custom десериализатор то
не пропускают код в production.
если интересно теория изложена здесь - https://adityagollapudi.wordpress.com/2 ... alization/
----- end of между делом

короче говоря я как мне кажется нашел решение - дело было в том что можно override readObject and writeObject в классе который Serializable. Таким образом можно вручную реализовать передачу Date и TimeStamp полей конвертировав их в строку например с определенным форматом. А строки в свою очередь передаются без проблем. при десериализации вызывается readobject и вручную делается конверсия из строки заданного формата в Date, TimeStamp.
сегодня уже сделал для Date - вроде работает. TimeStamp на полпути = завтра хочу доделать.

скорей всего проблема будет решена - но почему это происходит вопрос открытый. Date кстати тоже implements Serializable. в теории такие поля должны автоматически сериал/десериал по умолчанию. Так как это происходит с long, int, String....
java 1.8_112.

Return to “Вопросы и новости IT”