Ранее на этой неделе я хотел разработать 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 SerialiseMeSerialiseMe: 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!