選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

SerialVersionUID.java 7.7KB

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