我正在開發一個項目,該項目生成Java文件。我希望能夠像使用serialver工具一樣,選擇性地添加serialVersionUID
。如何在Java中以編程方式生成serialVersionUID?
有沒有辦法做到這一點,當我產生Java代碼,或者我需要問工具的用戶手動提供UID?要清楚,我不想通過Eclipse或serialver
工具自動執行此操作,而是通過Java本身執行此操作。
我正在開發一個項目,該項目生成Java文件。我希望能夠像使用serialver工具一樣,選擇性地添加serialVersionUID
。如何在Java中以編程方式生成serialVersionUID?
有沒有辦法做到這一點,當我產生Java代碼,或者我需要問工具的用戶手動提供UID?要清楚,我不想通過Eclipse或serialver
工具自動執行此操作,而是通過Java本身執行此操作。
有一個版本的serialver
工具源可用from OpenJDK。這一切都歸結到這一呼籲:
ObjectStreamClass c = ObjectStreamClass.lookup(MyClass.class);
long serialID = c.getSerialVersionUID();
System.out.println(serialID);
在JDK 6,至少它返回相同數量與serialver
工具。
嘗試正在生成的類的類名的哈希碼。
可能存在衝突,因爲散列碼並非唯一,但這些衝突在統計上不太可能。
Here's documentation關於如何生成serialVersionUID值。它比我想象的要複雜得多。
由於其複雜性,我要麼在UID中擁有用戶類型,要麼只是使用完整類名的簡單哈希。
/**
* 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());
}
}
@傑弗裏...很狡猾+1 –
如果您的工具生成全新的代碼,你沒有任何需要計算的方式serialver
一樣。只需使用1,或-1,或任何你喜歡的。
你能解釋一下爲什麼嗎?這是因爲它是一個新班級嗎? –
@bn。因爲它是一個新類,所以沒有現有的序列化,所以沒有什麼可兼容的。 – EJP
這是一個老的線程,但我猜,serialVersionUID仍然是熱門話題之一。
當我開始編寫Java代碼時,很難找到併爲我的變量分配一個唯一值給serlialVersionUID變量。過了一段時間,簡單的日期時間格式(yyyy-MM-ddTHH:mm:ss)給了我想法:爲什麼我不從當前日期和時間生成值?
因此,我開始根據當前日期和時間生成(當然是手動)值。
假設當前的日期和時間是01/09/2015 11:00 pm。我會將201601091100L值分配給serialVersionUID。
我希望這個想法可以幫助您進一步改善您的項目。
順便說一下,日期 - 時間字符串的格式由非常有用的[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格式/生成日期時間值的字符串表示。 –
也許正在生成的類的類名的哈希碼將工作? –
我在想這樣的事情,想知道是否有辦法做到這一點,儘管如此,相當於serialver工具。 –
當然,你可以像serialver工具那樣做。只需找到其「serialVersionUID」一代的邏輯。到目前爲止,我一直在尋找沒有成功。 –