Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

SerialVersionUID.java 7.7KB

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