2013-08-17 34 views
7

我正在開發一個項目,該項目生成Java文件。我希望能夠像使用serialver工具一樣,選擇性地添加serialVersionUID如何在Java中以編程方式生成serialVersionUID?

有沒有辦法做到這一點,當我產生Java代碼,或者我需要問工具的用戶手動提供UID?要清楚,我不想通過Eclipse或serialver工具自動執行此操作,而是通過Java本身執行此操作。

+0

也許正在生成的類的類名的哈希碼將工作? –

+0

我在想這樣的事情,想知道是否有辦法做到這一點,儘管如此,相當於serialver工具。 –

+0

當然,你可以像serialver工具那樣做。只需找到其「serialVersionUID」一代的邏輯。到目前爲止,我一直在尋找沒有成功。 –

回答

7

有一個版本的serialver工具源可用from OpenJDK。這一切都歸結到這一呼籲:

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

在JDK 6,至少它返回相同數量與serialver工具。

2

嘗試正在生成的類的類名的哈希碼。

可能存在衝突,因爲散列碼並非唯一,但這些衝突在統計上不太可能。

Here's documentation關於如何生成serialVersionUID值。它比我想象的要複雜得多。

由於其複雜性,我要麼在UID中擁有用戶類型,要麼只是使用完整類名的簡單哈希。

3

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

@傑弗裏...很狡猾+1 –

2

如果您的工具生成全新的代碼,你沒有任何需要計算的方式serialver一樣。只需使用1,或-1,或任何你喜歡的。

+0

你能解釋一下爲什麼嗎?這是因爲它是一個新班級嗎? –

+1

@bn。因爲它是一個新類,所以沒有現有的序列化,所以沒有什麼可兼容的。 – EJP

1

這是一個老的線程,但我猜,serialVersionUID仍然是熱門話題之一。

當我開始編寫Java代碼時,很難找到併爲我的變量分配一個唯一值給serlialVersionUID變量。過了一段時間,簡單的日期時間格式(yyyy-MM-ddTHH:mm:ss)給了我想法:爲什麼我不從當前日期和時間生成值?

因此,我開始根據當前日期和時間生成(當然是手動)值。

假設當前的日期和時間是01/09/2015 11:00 pm。我會將201601091100L值分配給serialVersionUID。

我希望這個想法可以幫助您進一步改善您的項目。

+0

順便說一下,日期 - 時間字符串的格式由非常有用的[ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)標準定義。如你所示,連字符和冒號是可選的,稱爲「基本」變體。內置於Java 8及更高版本中的[java.time](http://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html)框架在解析時默認使用ISO 8601格式/生成日期時間值的字符串表示。 –