2013-08-17 11 views
7

Pracuję nad projektem, który generuje pliki Java. Chciałbym opcjonalnie dodać serialVersionUID, tak jak w przypadku narzędzia serialver.Jak programowo generować serialVersionUID w Javie?

Czy istnieje sposób, aby to zrobić, gdy generuję kodJava Java lub będę musiał poprosić użytkownika narzędzia, aby dostarczyć identyfikatory UID ręcznie? Aby było jasne, nie zamierzam robić tego automatycznie za pomocą Eclipse lub narzędzia serialver, ale samemu to zrobić za pomocą samej Java.

+0

Może kod hashowy nazwy klasy, która jest generowana, zadziała? –

+0

Myślałem o czymś takim, zastanawiając się, czy istnieje sposób, aby to zrobić, co jest równoważne narzędziu seryjnego, jeśli to możliwe. –

+0

Oczywiście, możesz to zrobić tak, jak robi to narzędzie Servera. Po prostu znajdź logikę związaną z generacją "serialVersionUID". Jak dotąd szukałem bez żadnego sukcesu. –

Odpowiedz

7

Dostępna jest wersja narzędzia serialver dostępna jako from OpenJDK. To wszystko sprowadza się do tego wezwania:

ObjectStreamClass c = ObjectStreamClass.lookup(MyClass.class); 
long serialID = c.getSerialVersionUID(); 
System.out.println(serialID); 

W JDK 6 przynajmniej zwraca ten sam numer z serialver narzędzia.

2

Spróbuj hashcode nazwy klasy generowanej klasy.

Mogą wystąpić kolizje, ponieważ kod skrótu nie jest unikalny, ale te kolizje są statystycznie mało prawdopodobne.

Here's documentation na temat generowania wartości serialVersionUID. Jest o wiele bardziej skomplikowany, niż bym się domyślił.

Z powodu jego złożoności, powinienem mieć typ użytkownika w samym UID lub po prostu użyć prostego skrótu z pełną nazwą klasy.

3

Od ObjectStreamClass:

/** 
* Computes the default serial version UID value for the given class. 
*/ 
private static long computeDefaultSUID(Class<?> cl) { 
    if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl)) 
    { 
     return 0L; 
    } 

    try { 
     ByteArrayOutputStream bout = new ByteArrayOutputStream(); 
     DataOutputStream dout = new DataOutputStream(bout); 

     dout.writeUTF(cl.getName()); 

     int classMods = cl.getModifiers() & 
      (Modifier.PUBLIC | Modifier.FINAL | 
      Modifier.INTERFACE | Modifier.ABSTRACT); 

     /* 
     * compensate for javac bug in which ABSTRACT bit was set for an 
     * interface only if the interface declared methods 
     */ 
     Method[] methods = cl.getDeclaredMethods(); 
     if ((classMods & Modifier.INTERFACE) != 0) { 
      classMods = (methods.length > 0) ? 
       (classMods | Modifier.ABSTRACT) : 
       (classMods & ~Modifier.ABSTRACT); 
     } 
     dout.writeInt(classMods); 

     if (!cl.isArray()) { 
      /* 
      * compensate for change in 1.2FCS in which 
      * Class.getInterfaces() was modified to return Cloneable and 
      * Serializable for array classes. 
      */ 
      Class<?>[] interfaces = cl.getInterfaces(); 
      String[] ifaceNames = new String[interfaces.length]; 
      for (int i = 0; i < interfaces.length; i++) { 
       ifaceNames[i] = interfaces[i].getName(); 
      } 
      Arrays.sort(ifaceNames); 
      for (int i = 0; i < ifaceNames.length; i++) { 
       dout.writeUTF(ifaceNames[i]); 
      } 
     } 

     Field[] fields = cl.getDeclaredFields(); 
     MemberSignature[] fieldSigs = new MemberSignature[fields.length]; 
     for (int i = 0; i < fields.length; i++) { 
      fieldSigs[i] = new MemberSignature(fields[i]); 
     } 
     Arrays.sort(fieldSigs, new Comparator<MemberSignature>() { 
      public int compare(MemberSignature ms1, MemberSignature ms2) { 
       return ms1.name.compareTo(ms2.name); 
      } 
     }); 
     for (int i = 0; i < fieldSigs.length; i++) { 
      MemberSignature sig = fieldSigs[i]; 
      int mods = sig.member.getModifiers() & 
       (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | 
       Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE | 
       Modifier.TRANSIENT); 
      if (((mods & Modifier.PRIVATE) == 0) || 
       ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0)) 
      { 
       dout.writeUTF(sig.name); 
       dout.writeInt(mods); 
       dout.writeUTF(sig.signature); 
      } 
     } 

     if (hasStaticInitializer(cl)) { 
      dout.writeUTF("<clinit>"); 
      dout.writeInt(Modifier.STATIC); 
      dout.writeUTF("()V"); 
     } 

     Constructor[] cons = cl.getDeclaredConstructors(); 
     MemberSignature[] consSigs = new MemberSignature[cons.length]; 
     for (int i = 0; i < cons.length; i++) { 
      consSigs[i] = new MemberSignature(cons[i]); 
     } 
     Arrays.sort(consSigs, new Comparator<MemberSignature>() { 
      public int compare(MemberSignature ms1, MemberSignature ms2) { 
       return ms1.signature.compareTo(ms2.signature); 
      } 
     }); 
     for (int i = 0; i < consSigs.length; i++) { 
      MemberSignature sig = consSigs[i]; 
      int mods = sig.member.getModifiers() & 
       (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | 
       Modifier.STATIC | Modifier.FINAL | 
       Modifier.SYNCHRONIZED | Modifier.NATIVE | 
       Modifier.ABSTRACT | Modifier.STRICT); 
      if ((mods & Modifier.PRIVATE) == 0) { 
       dout.writeUTF("<init>"); 
       dout.writeInt(mods); 
       dout.writeUTF(sig.signature.replace('/', '.')); 
      } 
     } 

     MemberSignature[] methSigs = new MemberSignature[methods.length]; 
     for (int i = 0; i < methods.length; i++) { 
      methSigs[i] = new MemberSignature(methods[i]); 
     } 
     Arrays.sort(methSigs, new Comparator<MemberSignature>() { 
      public int compare(MemberSignature ms1, MemberSignature ms2) { 
       int comp = ms1.name.compareTo(ms2.name); 
       if (comp == 0) { 
        comp = ms1.signature.compareTo(ms2.signature); 
       } 
       return comp; 
      } 
     }); 
     for (int i = 0; i < methSigs.length; i++) { 
      MemberSignature sig = methSigs[i]; 
      int mods = sig.member.getModifiers() & 
       (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | 
       Modifier.STATIC | Modifier.FINAL | 
       Modifier.SYNCHRONIZED | Modifier.NATIVE | 
       Modifier.ABSTRACT | Modifier.STRICT); 
      if ((mods & Modifier.PRIVATE) == 0) { 
       dout.writeUTF(sig.name); 
       dout.writeInt(mods); 
       dout.writeUTF(sig.signature.replace('/', '.')); 
      } 
     } 

     dout.flush(); 

     MessageDigest md = MessageDigest.getInstance("SHA"); 
     byte[] hashBytes = md.digest(bout.toByteArray()); 
     long hash = 0; 
     for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) { 
      hash = (hash << 8) | (hashBytes[i] & 0xFF); 
     } 
     return hash; 
    } catch (IOException ex) { 
     throw new InternalError(); 
    } catch (NoSuchAlgorithmException ex) { 
     throw new SecurityException(ex.getMessage()); 
    } 
} 
+0

@Jeffrey ...Całkiem Crafty +1 –

2

Jeśli narzędzie generuje nowy kod nie ma żadnej potrzeby, aby obliczyć to tak serialver robi. Po prostu użyj 1 lub -1 lub cokolwiek chcesz.

+0

Czy mógłbyś wyjaśnić, dlaczego? Czy to dlatego, że jest to nowa klasa? –

+1

@bn. Ponieważ jest to nowa klasa, nie ma żadnych serializacji, więc nie ma nic, co można by z nią pogodzić. – EJP

1

To jest stary wątek, ale, jak sądzę, serialVersionUID jest wciąż jednym z gorących tematów.

Kiedy zacząłem pisać kod Javy, to było zbyt trudne do znalezienia i przypisać unikalną wartość serlialVersionUID zmienną dla mnie. Po chwili prosty format daty (yyyy-MM-ddTHH: mm: ss) dał mi pomysł: Dlaczego nie generuję wartości z bieżącej daty i godziny?

Tak więc zacząłem generować (oczywiście ręcznie) wartości zgodnie z bieżącą datą i godziną.

Załóżmy, że aktualna data i godzina to 01.09.2015 23:00. Przypisałbym wartość 201601091100L do serialVersionUID.

Mam nadzieję, że ten pomysł pomoże w dalszym ulepszaniu projektów.

+0

Nawiasem mówiąc, ten format ciągów daty i czasu jest określony przez bardzo przydatny standard [ISO 8601] (https://en.wikipedia.org/wiki/ISO_8601). Łączniki i dwukropki są opcjonalne, jak pokazałeś, zwane "podstawową" odmianą. Platforma [java.time] (http://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html) wbudowana w Javę 8 i później używa domyślnie formatów ISO 8601 w analizie składniowej/generowanie reprezentacji ciągów wartości daty i godziny. –

Powiązane problemy