Ранее на этой неделе я хотел разработать serialVersionUID сериализуемого класса, чтобы я мог переопределить его метод toString, не нарушая ничего.
Я наткнулся на сообщение в блоге Фрэнка Кима, в котором предлагалось использовать инструмент serialver , поставляемый с JDK.
Я создал небольшой проект Maven, чтобы протестировать этот инструмент на очень простом классе:
1
2
3
4
5
6
|
import java.io.Serializable; public class SerialiseMe implements Serializable { } |
Если мы скомпилируем этот класс в JAR, а затем запустим инструмент serialver , мы увидим следующий вывод:
1
2
|
$ serialver -classpath target /serialiser-0 .0.1-SNAPSHOT.jar SerialiseMe SerialiseMe: static final long serialVersionUID = -6060222249255158490L; |
Я хотел быстро подтвердить, что могу сериализовать и десериализовать этот класс, используя это значение, поэтому я написал следующий фрагмент кода для сериализации класса (когда у него не было серийного UID версии):
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
public class Serialiser { public static void main( String[] args ) throws IOException, ClassNotFoundException { ByteArrayOutputStream bout = new ByteArrayOutputStream( ); ObjectOutputStream oout = new ObjectOutputStream( bout ); Object value = new SerialiseMe(); oout.writeObject( value ); oout.close(); byte [] bytes = bout.toByteArray(); FileOutputStream fileOuputStream = new FileOutputStream( "/tmp/foo.txt" ); fileOuputStream.write(bytes); fileOuputStream.close(); } } |
После этого я написал следующий фрагмент кода для десериализации файла:
01
02
03
04
05
06
07
08
09
10
11
12
|
public class Deserialiser { public static void main( String[] args ) throws IOException, ClassNotFoundException { FileInputStream fileInputStream = new FileInputStream( new File( "/tmp/foo.txt" ) ); byte [] bytes = IOUtils.toByteArray( fileInputStream ); ByteArrayInputStream in = new ByteArrayInputStream( bytes, 0 , bytes.length ); ObjectInputStream oin = new ObjectInputStream( in ); Object object = oin.readObject(); } } |
Я подключил серийную версию UID к классу и смог правильно десериализовать его. Я попытался изменить одну из цифр, просто чтобы убедиться, что она взорвется, и это действительно так:
1
2
3
4
5
6
|
import java.io.Serializable; public class SerialiseMe implements Serializable { static final long serialVersionUID = -6060222249255158491L; } |
01
02
03
04
05
06
07
08
09
10
11
12
13
|
Exception in thread "main" java.io.InvalidClassException: SerialiseMe; local class incompatible: stream classdesc serialVersionUID = - 6060222249255158490 , local class serialVersionUID = - 6060222249255158491 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java: 604 ) at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java: 1620 ) at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java: 1515 ) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java: 1769 ) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java: 1348 ) at java.io.ObjectInputStream.readObject(ObjectInputStream.java: 370 ) at Deserialiser.main(Deserialiser.java: 18 ) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java: 57 ) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java: 43 ) at java.lang.reflect.Method.invoke(Method.java: 601 ) at com.intellij.rt.execution.application.AppMain.main(AppMain.java: 120 ) |
serialver #ftw!