2009-08-24 13 views
18

Czy istnieje sposób określenia wygenerowanego serialVersionUID serializowanego obiektu Java?Znajdowanie numeru seryjnego seryjnego obiektu

Problem polega na tym, że serializowałem obiekt bez wyraźnego określenia wartości serialVersionUID. Teraz proces deserializacji narzeka na niezgodności klas. Jednak nie zmieniłem klasy w sposób, który spowodowałby jej niezgodność. Zakładam więc, że wystarczy podać w klasie klasę serialVersionUID, ponieważ jest ona przechowywana w danych obiektu. W tym celu muszę przeczytać serialVersionUID z zserializowanych danych.

+0

Co dzieje się w przypadku dodania metody do klasy? Czy starszy, serializowany obiekt może zostać odczytany przy użyciu zmodyfikowanej klasy serializowanej? – sprezzatura

+0

Metody nie stanowią stanu obiektu, więc nie ma problemu z odczytaniem serializowanego obiektu, chyba że nie korzystasz z żadnego serialVersionUID .. –

Odpowiedz

12

Można to zrobić poprzez rozszerzenie ObjectInputStream:

public class PrintUIDs extends ObjectInputStream { 

    public PrintUIDs(InputStream in) throws IOException { 
    super(in); 
    } 

    @Override 
    protected ObjectStreamClass readClassDescriptor() throws IOException, 
     ClassNotFoundException { 
    ObjectStreamClass descriptor = super.readClassDescriptor(); 
    System.out.println("name=" + descriptor.getName()); 
    System.out.println("serialVersionUID=" + descriptor.getSerialVersionUID()); 
    return descriptor; 
    } 

    public static void main(String[] args) throws IOException, 
     ClassNotFoundException { 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    ObjectOutputStream oos = new ObjectOutputStream(baos); 
    List<Object> list = Arrays.asList((Object) new Date(), UUID.randomUUID()); 
    oos.writeObject(list); 
    oos.close(); 
    InputStream in = new ByteArrayInputStream(baos.toByteArray()); 
    ObjectInputStream ois = new PrintUIDs(in); 
    ois.readObject(); 
    } 

} 

wierzę, że byłoby to możliwe, aby odczytać wszystkie dane odcinkach zastępując deskryptor zwrócony przez metodę, ale nie próbowałem go.

0

To jest dokładnie to, co powinieneś zrobić - określić własną static final long serialVersionUID.

Istnieje sekcja o tym w dokumentach dla Serializable.

Jeśli nie podałeś numeru serialVersionUID, nie sądzę, że istnieje łatwy sposób na uzyskanie go poza odszyfrowaniem strumienia, jak sugeruje @WMR.

+0

Należy pamiętać, że powinien on mieć nazwę serialVersionUID (nie: serialversionuid - Java rozróżnia małe i wielkie litery), a powinny być prywatne statyczne końcowe długo). – Jesper

+0

Zgadzam się. Ale czy istnieje sposób na odczytanie wygenerowanego identyfikatora uid z zserializowanych danych? – paweloque

5

Z serializowanymi bitami powiązane są metadane (nagłówek, jeśli chcesz). Możesz odczytać wartość z metadanych, jeśli wiesz, w którym miejscu jest (zapisano tam SerialVersionUID wraz z innymi informacjami, takimi jak nazwa klasy).

Myślę, że ten artykuł może pomóc: The Java serialization algorithm revealed.

Należy zauważyć, że bity są zapisywane "w czystej postaci" (chyba że zaszyfrowałeś strumień jawnie), więc edytor HEX może być wszystkim, czego potrzebujesz, aby zobaczyć, co to jest SerialVersionUID.

21

Jest to łatwy sposób, aby dowiedzieć się serialVersionUID z wykładowa

Załóżmy, że masz klasę, w której zapomniałem wspomnieć serialversionUID-

import java.io.Serializable; 

public class TestSerializable implements Serializable { 

} 

Wystarczy zrobić this-

serialver -classpath . TestSerializable 

To drukuje -

static final long serialVersionUID = 5832063776451490808L; 

serialver to narzędzie, które przychodzi wraz z JDK

+2

Ale to działa tylko, jeśli masz starą wersję klasy TestSerializable. problem lewapa polega na tym, że nie wie, jaka była wartość serialVersionUID w starej wersji klasy obiektu, który serializował. Jeśli nie ma już starej wersji klasy, nie może użyć serialver, aby się tego dowiedzieć. – Jesper

+0

do tego służy kontrola wersji. – james

13

Działa to dla mnie:

long serialVersionUID = ObjectStreamClass.lookup(YourObject.getClass()).getSerialVersionUID(); 

Nadzieję, że pomaga też.

0

jest znacznie prostszy sposób, aby uzyskać serialVersionUID na odcinkach obiektu - tylko deserializować go z Apache Commons serializacji utils do tej samej klasy z innej wersji seryjny UID i odczytać komunikat wyjątku, który będzie bardziej lub mniej:

org.apache.commons.lang.SerializationException: java.io.InvalidClassException: my.example.SerializableClass; miejscowy klasa niezgodne: strumień ClassDesc serialVersionUID = -1, lokalna klasa serialVersionUID = -2

0

enter image description here dla programistów Android,

można również włączyć inspekcję serializacji z Ustawienia -> Edytor -> Kontrole -> enable "Serializowalna klasa bez" serialVersionUID "sprawdź" najpierw, potem ALT + ENTER, studio stworzy dla ciebie serialVersionUID.

Powiązane problemy