You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SerialVersionUID.java 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved.
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. Alternatively, the contents of this file may be used under
  8. * the terms of the GNU Lesser General Public License Version 2.1 or later.
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. */
  15. package javassist;
  16. import java.io.*;
  17. import javassist.bytecode.*;
  18. import java.util.*;
  19. import java.security.*;
  20. /**
  21. * Utility for calculating serialVersionUIDs for Serializable classes.
  22. *
  23. * @author Bob Lee (crazybob@crazybob.org)
  24. * @author modified by Shigeru Chiba
  25. */
  26. public class SerialVersionUID {
  27. /**
  28. * Adds serialVersionUID if one does not already exist. Call this before
  29. * modifying a class to maintain serialization compatability.
  30. */
  31. public static void setSerialVersionUID(CtClass clazz)
  32. throws CannotCompileException, NotFoundException
  33. {
  34. // check for pre-existing field.
  35. try {
  36. clazz.getDeclaredField("serialVersionUID");
  37. return;
  38. }
  39. catch (NotFoundException e) {}
  40. // check if the class is serializable.
  41. if (!isSerializable(clazz))
  42. return;
  43. // add field with default value.
  44. CtField field = new CtField(CtClass.longType, "serialVersionUID",
  45. clazz);
  46. field.setModifiers(Modifier.PRIVATE | Modifier.STATIC |
  47. Modifier.FINAL);
  48. clazz.addField(field, calculateDefault(clazz) + "L");
  49. }
  50. /**
  51. * Does the class implement Serializable?
  52. */
  53. private static boolean isSerializable(CtClass clazz)
  54. throws NotFoundException
  55. {
  56. ClassPool pool = clazz.getClassPool();
  57. return clazz.subtypeOf(pool.get("java.io.Serializable"));
  58. }
  59. /**
  60. * Calculate default value. See Java Serialization Specification, Stream
  61. * Unique Identifiers.
  62. */
  63. static long calculateDefault(CtClass clazz)
  64. throws CannotCompileException
  65. {
  66. try {
  67. ByteArrayOutputStream bout = new ByteArrayOutputStream();
  68. DataOutputStream out = new DataOutputStream(bout);
  69. ClassFile classFile = clazz.getClassFile();
  70. // class name.
  71. String javaName = javaName(clazz);
  72. out.writeUTF(javaName);
  73. // class modifiers.
  74. out.writeInt(clazz.getModifiers() & (Modifier.PUBLIC |
  75. Modifier.FINAL | Modifier.INTERFACE | Modifier.ABSTRACT));
  76. // interfaces.
  77. String[] interfaces = classFile.getInterfaces();
  78. for (int i = 0; i < interfaces.length; i++)
  79. interfaces[i] = javaName(interfaces[i]);
  80. Arrays.sort(interfaces);
  81. for (int i = 0; i < interfaces.length; i++)
  82. out.writeUTF(interfaces[i]);
  83. // fields.
  84. CtField[] fields = clazz.getDeclaredFields();
  85. Arrays.sort(fields, new Comparator() {
  86. public int compare(Object o1, Object o2) {
  87. CtField field1 = (CtField)o1;
  88. CtField field2 = (CtField)o2;
  89. return field1.getName().compareTo(field2.getName());
  90. }
  91. });
  92. for (int i = 0; i < fields.length; i++) {
  93. CtField field = (CtField) fields[i];
  94. int mods = field.getModifiers();
  95. if (((mods & Modifier.PRIVATE) == 0) ||
  96. ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0)) {
  97. out.writeUTF(field.getName());
  98. out.writeInt(mods);
  99. out.writeUTF(field.getFieldInfo2().getDescriptor());
  100. }
  101. }
  102. // static initializer.
  103. if (classFile.getStaticInitializer() != null) {
  104. out.writeUTF("<clinit>");
  105. out.writeInt(Modifier.STATIC);
  106. out.writeUTF("()V");
  107. }
  108. // constructors.
  109. CtConstructor[] constructors = clazz.getDeclaredConstructors();
  110. Arrays.sort(constructors, new Comparator() {
  111. public int compare(Object o1, Object o2) {
  112. CtConstructor c1 = (CtConstructor)o1;
  113. CtConstructor c2 = (CtConstructor)o2;
  114. return c1.getMethodInfo2().getDescriptor().compareTo(
  115. c2.getMethodInfo2().getDescriptor());
  116. }
  117. });
  118. for (int i = 0; i < constructors.length; i++) {
  119. CtConstructor constructor = constructors[i];
  120. int mods = constructor.getModifiers();
  121. if ((mods & Modifier.PRIVATE) == 0) {
  122. out.writeUTF("<init>");
  123. out.writeInt(mods);
  124. out.writeUTF(constructor.getMethodInfo2()
  125. .getDescriptor().replace('/', '.'));
  126. }
  127. }
  128. // methods.
  129. CtMethod[] methods = clazz.getDeclaredMethods();
  130. Arrays.sort(methods, new Comparator() {
  131. public int compare(Object o1, Object o2) {
  132. CtMethod m1 = (CtMethod)o1;
  133. CtMethod m2 = (CtMethod)o2;
  134. int value = m1.getName().compareTo(m2.getName());
  135. if (value == 0)
  136. value = m1.getMethodInfo2().getDescriptor()
  137. .compareTo(m2.getMethodInfo2().getDescriptor());
  138. return value;
  139. }
  140. });
  141. for (int i = 0; i < methods.length; i++) {
  142. CtMethod method = methods[i];
  143. int mods = method.getModifiers();
  144. if ((mods & Modifier.PRIVATE) == 0) {
  145. out.writeUTF(method.getName());
  146. out.writeInt(mods);
  147. out.writeUTF(method.getMethodInfo2()
  148. .getDescriptor().replace('/', '.'));
  149. }
  150. }
  151. // calculate hash.
  152. out.flush();
  153. MessageDigest digest = MessageDigest.getInstance("SHA");
  154. byte[] digested = digest.digest(bout.toByteArray());
  155. long hash = 0;
  156. for (int i = Math.min(digested.length, 8) - 1; i >= 0; i--)
  157. hash = (hash << 8) | (digested[i] & 0xFF);
  158. return hash;
  159. }
  160. catch (IOException e) {
  161. throw new CannotCompileException(e);
  162. }
  163. catch (NoSuchAlgorithmException e) {
  164. throw new CannotCompileException(e);
  165. }
  166. }
  167. private static String javaName(CtClass clazz) {
  168. return Descriptor.toJavaName(Descriptor.toJvmName(clazz));
  169. }
  170. private static String javaName(String name) {
  171. return Descriptor.toJavaName(Descriptor.toJvmName(name));
  172. }
  173. }