привет всем. может кто-то сталкивался подробно
пытаюсь сериализовать 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 также
есть какие другие варианты ?
deserialization issue
-
- Уже с Приветом
- Posts: 4827
- Joined: 15 May 2001 09:01
-
- Новичок
- Posts: 49
- Joined: 07 Apr 2016 03:53
Re: deserialization issue
@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);
}
на данный момент вопрос уперся в проблему
согласно 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);
}
-
- Уже с Приветом
- Posts: 4827
- Joined: 15 May 2001 09:01
Re: deserialization issue
Вы бы программку небольшую, которая не работает, показали. Ну или задачу сформулировали бы. То, что по Вашей последней ссылке - неудачная попытка "быстро, на коленке" заткнуть дыру в безопасности, порождённую Object[In|Out]putStream.
Если Вам необходимо передать данные между двумя явами, не надо использовать означенные потоки объектов. Раньше стандартом было использование обычных потоков данных через сокеты, которые упаковывались-распаковывались в форматах специфичных для протокола обмена. Сейчас сервера раздают данные через http REST сервисы с использованием какой имплементации javax.ws.rs.
Если Вам необходимо передать данные между двумя явами, не надо использовать означенные потоки объектов. Раньше стандартом было использование обычных потоков данных через сокеты, которые упаковывались-распаковывались в форматах специфичных для протокола обмена. Сейчас сервера раздают данные через http REST сервисы с использованием какой имплементации javax.ws.rs.
-
- Новичок
- Posts: 49
- Joined: 07 Apr 2016 03:53
Re: deserialization issue
привет всем !
вот собственно программа
проблема в том что при десериализации объекта 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
}
}
вот собственно программа
проблема в том что при десериализации объекта 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
}
}
-
- Уже с Приветом
- Posts: 4827
- Joined: 15 May 2001 09:01
Re: deserialization issue
Перед тем, как залезать в дебри кода, давайте решим вопрос по архитектуре.
Вы отдаёте данные в обёртке HTTP: RequestMapping в коде стоит, полагаю, из-за этого. HTTP по определению платформенно-независимый. Отдаёте Вы простой набор полей int/String/Date, который тоже платформенно-независимый. Но вместо того, чтобы отдавать набор в платформенно-независимом контейнере типа JSON или XML, Вы его отдаёте в Java-specific формате ObjectOutputStream. Принимать этот формат - прямая хирургия мозгов JVM. Чтобы в нём принимать данные надо быть абсолютно уверенным в чистых руках выдающего данные в этом формате. Судя по тому, что на входе десериализатора стоит простая проверка в resolveClass, уверенности в чистоте рук таки нет.
Я бы предложил сменить формат обмена c бинарного ObjectOutputStream на текстовый JSON. При этом наблюдаемая проблема уйдёт совсем. Вместе с ней уйдут проблемы "грязных рук" и прочий бардак с бинарной несовместимостью. Давайте так сделаем? Ну или расскажите: есть ли причины держать бинарный формат обмена.
Вы отдаёте данные в обёртке HTTP: RequestMapping в коде стоит, полагаю, из-за этого. HTTP по определению платформенно-независимый. Отдаёте Вы простой набор полей int/String/Date, который тоже платформенно-независимый. Но вместо того, чтобы отдавать набор в платформенно-независимом контейнере типа JSON или XML, Вы его отдаёте в Java-specific формате ObjectOutputStream. Принимать этот формат - прямая хирургия мозгов JVM. Чтобы в нём принимать данные надо быть абсолютно уверенным в чистых руках выдающего данные в этом формате. Судя по тому, что на входе десериализатора стоит простая проверка в resolveClass, уверенности в чистоте рук таки нет.
Я бы предложил сменить формат обмена c бинарного ObjectOutputStream на текстовый JSON. При этом наблюдаемая проблема уйдёт совсем. Вместе с ней уйдут проблемы "грязных рук" и прочий бардак с бинарной несовместимостью. Давайте так сделаем? Ну или расскажите: есть ли причины держать бинарный формат обмена.
-
- Новичок
- Posts: 49
- Joined: 07 Apr 2016 03:53
Re: deserialization issue
сорри что возможно ввел в заблуждение показал контроллер с 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.
----- между делом
если интересно там просто 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.