KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > versant > core > jdo > tools > enhancer > utils > SerialUIDHelper


1
2 /*
3  * Copyright (c) 1998 - 2005 Versant Corporation
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  * Versant Corporation - initial API and implementation
11  */

12 package com.versant.core.jdo.tools.enhancer.utils;
13
14 import com.versant.lib.bcel.classfile.JavaClass;
15 import com.versant.lib.bcel.classfile.Method;
16 import com.versant.lib.bcel.classfile.Field;
17 import com.versant.lib.bcel.Repository;
18 import com.versant.lib.bcel.Constants;
19
20 import java.io.ByteArrayOutputStream JavaDoc;
21 import java.io.DataOutputStream JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.security.MessageDigest JavaDoc;
24 import java.security.DigestOutputStream JavaDoc;
25 import java.security.NoSuchAlgorithmException JavaDoc;
26 import java.util.*;
27
28
29
30 /**
31  */

32 public class SerialUIDHelper {
33
34     /**
35      * Find out if the class has a static class initializer <clinit>
36      *
37      */

38     private static boolean hasStaticInitializer(JavaClass javaClass){
39         Method[] methods = javaClass.getMethods();
40         for(int i = 0; i < methods.length; i++) {
41             Method m = methods[i];
42             if (m.getName().equals("<clinit>")){//static constructor = <clinit>
43
return true;
44             }
45         }
46         return false;
47     }
48
49     private static Comparator compareMethodBySig = new SerialUIDHelper.MethodSortSig();
50
51     private static class MethodSortSig implements Comparator {
52         public int compare(Object JavaDoc a, Object JavaDoc b){
53             Method methodA = (Method)a;
54             Method methodB = (Method)b;
55             String JavaDoc sigA = methodA.getSignature();
56             String JavaDoc sigB = methodB.getSignature();
57             return sigA.compareTo(sigB);
58         }
59     }
60
61     private static Comparator compareMethodByName = new SerialUIDHelper.MethodSortName();
62
63     private static class MethodSortName implements Comparator {
64         public int compare(Object JavaDoc a, Object JavaDoc b){
65             Method methodA = (Method)a;
66             Method methodB = (Method)b;
67             String JavaDoc sigA = methodA.getName();
68             String JavaDoc sigB = methodB.getName();
69             return sigA.compareTo(sigB);
70         }
71     }
72
73     private static Comparator compareFieldByName = new SerialUIDHelper.FieldSort();
74
75     private static class FieldSort implements Comparator {
76         public int compare(Object JavaDoc a, Object JavaDoc b){
77             Field fieldA = (Field)a;
78             Field fieldB = (Field)b;
79             return fieldA.getName().compareTo(fieldB.getName());
80         }
81     }
82
83     /*
84      * Comparator object for Classes and Interfaces
85      */

86     private static Comparator compareStringByName = new SerialUIDHelper.CompareStringByName();
87
88     private static class CompareStringByName implements Comparator {
89         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
90             String JavaDoc c1 = (String JavaDoc)o1;
91             String JavaDoc c2 = (String JavaDoc)o2;
92             return c1.compareTo(c2);
93         }
94     }
95
96     private static Set removePrivateConstructorsAndSort(JavaClass javaClass){
97         TreeSet set = new TreeSet(compareMethodBySig);
98         Method[] methods = javaClass.getMethods();
99         for(int i = 0; i < methods.length; i++) {
100             com.versant.lib.bcel.classfile.Method m = methods[i];
101             if (m.getName().equals("<init>") && (!m.isPrivate())){
102                 set.add(m);
103             }
104         }
105         return set;
106     }
107
108     private static Set removePrivateAndConstructorsAndSort(JavaClass javaClass){
109         TreeSet set = new TreeSet(compareMethodByName);
110         Method[] methods = javaClass.getMethods();
111         for(int i = 0; i < methods.length; i++) {
112             Method m = methods[i];
113             if (!m.getName().startsWith("<")){
114                 if (!m.isPrivate()){
115                      set.add(m);
116                 }
117             }
118         }
119         return set;
120     }
121
122
123     /*
124      * Compute a hash for the specified class. Incrementally add
125      * items to the hash accumulating in the digest stream.
126      * Fold the hash into a long. Use the SHA secure hash function.
127      */

128     public static long computeSerialVersionUID(JavaClass clazz) {
129         ByteArrayOutputStream JavaDoc devnull = new ByteArrayOutputStream JavaDoc(512);
130
131         long h = 0;
132         try {
133             MessageDigest JavaDoc md = MessageDigest.getInstance("SHA");
134             DigestOutputStream JavaDoc mdo = new DigestOutputStream JavaDoc(devnull, md);
135             DataOutputStream JavaDoc data = new DataOutputStream JavaDoc(mdo);
136
137             data.writeUTF(clazz.getClassName());
138 // System.out.println("-> "+clazz.getClassName());
139

140
141             int classaccess = clazz.getAccessFlags();
142             classaccess &= (Constants.ACC_PUBLIC | Constants.ACC_FINAL |
143                 Constants.ACC_INTERFACE | Constants.ACC_ABSTRACT);
144
145             /* Workaround for javac bug that only set ABSTRACT for
146             * interfaces if the interface had some methods.
147             * The ABSTRACT bit reflects that the number of methods > 0.
148             * This is required so correct hashes can be computed
149             * for existing class files.
150             * Previously this hack was present in the VM.
151             */

152             Method[] method = clazz.getMethods();
153             if ((classaccess & Constants.ACC_INTERFACE) != 0) {
154                 classaccess &= (~Constants.ACC_ABSTRACT);
155                 if (method.length > 0) {
156                     classaccess |= Constants.ACC_ABSTRACT;
157                 }
158             }
159
160             data.writeInt(classaccess);
161 // System.out.println("-> "+classaccess);
162

163             /*
164             * Get the list of interfaces supported,
165             * Accumulate their names in Lexical order
166             * and add them to the hash
167             */

168
169             String JavaDoc interfaces[] = clazz.getInterfaceNames();
170             Arrays.sort(interfaces, compareStringByName);
171
172             for (int i = 0; i < interfaces.length; i++) {
173                 data.writeUTF(interfaces[i]);
174 // System.out.println("-> "+interfaces[i]);
175
}
176
177
178             /* Sort the field names to get a deterministic order */
179             com.versant.lib.bcel.classfile.Field[] field = clazz.getFields();
180             Arrays.sort(field, compareFieldByName);
181
182             for (int i = 0; i < field.length; i++) {
183                 Field f = field[i];
184
185                 /* Include in the hash all fields except those that are
186                 * private transient and private static.
187                 */

188                 int m = f.getAccessFlags();
189                 if ((f.isPrivate() && f.isStatic()) ||
190                     (f.isPrivate() && f.isTransient())){
191                     continue;
192                 }
193
194                 data.writeUTF(f.getName());
195 //System.out.println("-> "+f.getName()+m+f.getSignature());
196
data.writeInt(m);
197                 data.writeUTF(f.getSignature());
198
199             }
200 //System.out.println("-------------------------------------------");
201
if (hasStaticInitializer(clazz)) {
202                 data.writeUTF("<clinit>");
203 //System.out.println("-> <clinit>"+Constants.ACC_STATIC+"()V");
204
data.writeInt(Constants.ACC_STATIC); // TBD: what modifiers does it have
205
data.writeUTF("()V");
206
207             }
208 //System.out.println("-------------------------------------------");
209
/*
210             * Get the list of constructors including name and signature
211             * Sort lexically, add all except the private constructors
212             * to the hash with their access flags
213             */

214
215             Iterator nonPrivateConstructorsIter = removePrivateConstructorsAndSort(clazz).iterator();
216             while (nonPrivateConstructorsIter.hasNext()){
217                 Method m = (Method)nonPrivateConstructorsIter.next();
218                 String JavaDoc mname = "<init>";
219                 String JavaDoc desc = m.getSignature();
220                 desc = desc.replace('/', '.');
221                 data.writeUTF(mname);
222 // System.out.println("-> "+mname+m.getAccessFlags()+desc);
223
data.writeInt(m.getAccessFlags());
224                 data.writeUTF(desc);
225             }
226 //System.out.println("-------------------------------------------");
227

228             /* Include in the hash all methods except those that are
229             * private transient and private static.
230             */

231
232             Iterator nonPrivateAndNoConstructorsIter = removePrivateAndConstructorsAndSort(clazz).iterator();
233             while (nonPrivateAndNoConstructorsIter.hasNext()){
234                 Method m = (Method)nonPrivateAndNoConstructorsIter.next();
235                 String JavaDoc mname = m.getName();
236                 String JavaDoc desc = m.getSignature();
237                 desc = desc.replace('/', '.');
238                 data.writeUTF(mname);
239 // System.out.println("-> "+mname+m.getAccessFlags()+desc);
240
data.writeInt(m.getAccessFlags());
241                 data.writeUTF(desc);
242             }
243 //System.out.println("-------------------------------------------");
244
/* Compute the hash value for this class.
245             * Use only the first 64 bits of the hash.
246             */

247             data.flush();
248             byte hasharray[] = md.digest();
249             for (int i = 0; i < Math.min(8, hasharray.length); i++) {
250                 h += (long)(hasharray[i] & 255) << (i * 8);
251             }
252         } catch (IOException JavaDoc ignore) {
253             /* can't happen, but be deterministic anyway. */
254             h = -1;
255         } catch (NoSuchAlgorithmException JavaDoc complain) {
256             throw new SecurityException JavaDoc(complain.getMessage());
257         }
258         return h;
259     }
260
261 }
262
Popular Tags