KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > Initializer


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21 package proguard;
22
23 import proguard.classfile.ClassPool;
24 import proguard.classfile.attribute.visitor.AllAttributeVisitor;
25 import proguard.classfile.instruction.visitor.AllInstructionVisitor;
26 import proguard.classfile.util.*;
27 import proguard.classfile.visitor.*;
28 import proguard.util.ClassNameListMatcher;
29
30 import java.io.IOException JavaDoc;
31 import java.util.*;
32
33 /**
34  * This class initializes class pools.
35  *
36  * @author Eric Lafortune
37  */

38 public class Initializer
39 {
40     private Configuration configuration;
41
42
43     /**
44      * Creates a new Initializer to initialize classes according to the given
45      * configuration.
46      */

47     public Initializer(Configuration configuration)
48     {
49         this.configuration = configuration;
50     }
51
52
53     /**
54      * Initializes the classes in the given program class pool and library class
55      * pool, performs some basic checks, and shrinks the library class pool.
56      */

57     public void execute(ClassPool programClassPool,
58                         ClassPool libraryClassPool) throws IOException JavaDoc
59     {
60         int originalLibraryClassPoolSize = libraryClassPool.size();
61
62         // Initialize the superclass hierarchy for program classes.
63
WarningPrinter hierarchyWarningPrinter = configuration.warn ?
64             new WarningPrinter(System.err) :
65             null;
66
67         programClassPool.classesAccept(
68             new ClassSuperHierarchyInitializer(programClassPool,
69                                                libraryClassPool,
70                                                hierarchyWarningPrinter));
71
72         // Initialize the superclass hierarchy for library classes.
73
libraryClassPool.classesAccept(
74             new ClassSuperHierarchyInitializer(programClassPool,
75                                                libraryClassPool,
76                                                null));
77
78         // Initialize the Class.forName and .class references.
79
WarningPrinter classForNameNotePrinter = configuration.note ?
80             new WarningPrinter(System.out) :
81             null;
82
83         programClassPool.classesAccept(
84             new AllMethodVisitor(
85             new AllAttributeVisitor(
86             new AllInstructionVisitor(
87             new DynamicClassReferenceInitializer(programClassPool,
88                                                  libraryClassPool,
89                                                  classForNameNotePrinter,
90                                                  createClassNoteExceptionMatcher(configuration.keep))))));
91
92         // Initialize the class references of program class members and attributes.
93
WarningPrinter referenceWarningPrinter = configuration.warn ?
94             new WarningPrinter(System.err) :
95             null;
96
97         programClassPool.classesAccept(
98             new ClassReferenceInitializer(programClassPool,
99                                           libraryClassPool,
100                                           referenceWarningPrinter));
101
102         // Initialize the Class.get[Declared]{Field,Method} references.
103
WarningPrinter getMemberNotePrinter = configuration.note ?
104             new WarningPrinter(System.out) :
105             null;
106
107         programClassPool.classesAccept(
108             new AllMethodVisitor(
109             new AllAttributeVisitor(
110             new AllInstructionVisitor(
111             new DynamicMemberReferenceInitializer(getMemberNotePrinter,
112                                                   createClassMemberNoteExceptionMatcher(configuration.keep, true),
113                                                   createClassMemberNoteExceptionMatcher(configuration.keep, false))))));
114
115         // Print various notes, if specified.
116
WarningPrinter fullyQualifiedClassNameNotePrinter =
117             new WarningPrinter(System.out);
118
119         WarningPrinter descriptorKeepNotePrinter =
120             new WarningPrinter(System.out);
121
122         if (configuration.note)
123         {
124             new FullyQualifiedClassNameChecker(programClassPool,
125                                                libraryClassPool,
126                                                fullyQualifiedClassNameNotePrinter).checkClassSpecifications(configuration.keep);
127
128             new DescriptorKeepChecker(programClassPool,
129                                       libraryClassPool,
130                                       descriptorKeepNotePrinter).checkClassSpecifications(configuration.keep);
131         }
132
133         // Reconstruct a library class pool with only those library classes
134
// whose hierarchies are referenced by the program classes. We can't do
135
// this if we later have to come up with the obfuscated class member
136
// names that are globally unique.
137
if (configuration.useUniqueClassMemberNames)
138         {
139             // Initialize the class references of library class members.
140
libraryClassPool.classesAccept(
141                 new ClassReferenceInitializer(programClassPool,
142                                               libraryClassPool,
143                                               null));
144         }
145         else
146         {
147             ClassPool referencedLibraryClassPool = new ClassPool();
148
149             // Collect the library classes that are referenced by program
150
// classes.
151
programClassPool.classesAccept(
152                 new ReferencedClassVisitor(
153                 new LibraryClassFilter(
154                 new ClassHierarchyTraveler(true, true, true, false,
155                 new LibraryClassFilter(
156                 new ClassPoolFiller(referencedLibraryClassPool))))));
157
158             // Initialize the class references of library class members.
159
referencedLibraryClassPool.classesAccept(
160                 new ClassReferenceInitializer(programClassPool,
161                                               libraryClassPool,
162                                               null));
163
164             // Reset the library class pool.
165
libraryClassPool.clear();
166
167             // Copy the library classes that are referenced directly by program
168
// classes and the library classes that are referenced by referenced
169
// library classes.
170
referencedLibraryClassPool.classesAccept(
171                 new MultiClassVisitor(new ClassVisitor[]
172                 {
173                     new ClassHierarchyTraveler(true, true, true, false,
174                     new LibraryClassFilter(
175                     new ClassPoolFiller(libraryClassPool))),
176
177                     new ReferencedClassVisitor(
178                     new LibraryClassFilter(
179                     new ClassHierarchyTraveler(true, true, true, false,
180                     new LibraryClassFilter(
181                     new ClassPoolFiller(libraryClassPool)))))
182                 }));
183         }
184
185         // Initialize the subclass hierarchies.
186
programClassPool.classesAccept(new ClassSubHierarchyInitializer());
187         libraryClassPool.classesAccept(new ClassSubHierarchyInitializer());
188
189         // Share strings between the classes, to reduce heap memory usage.
190
programClassPool.classesAccept(new StringSharer());
191         libraryClassPool.classesAccept(new StringSharer());
192
193         // Print out a summary of the notes, if necessary.
194
if (configuration.note)
195         {
196             int fullyQualifiedNoteCount = fullyQualifiedClassNameNotePrinter.getWarningCount();
197             if (fullyQualifiedNoteCount > 0)
198             {
199                 System.out.println("Note: there were " + fullyQualifiedNoteCount +
200                                    " references to unknown classes.");
201                 System.out.println(" You should check your configuration for typos.");
202             }
203
204             int descriptorNoteCount = descriptorKeepNotePrinter.getWarningCount();
205             if (descriptorNoteCount > 0)
206             {
207                 System.out.println("Note: there were " + descriptorNoteCount +
208                                    " unkept descriptor classes in kept class members.");
209                 System.out.println(" You should consider explicitly keeping the mentioned classes");
210                 System.out.println(" (using '-keep').");
211             }
212
213             int classForNameNoteCount = classForNameNotePrinter.getWarningCount();
214             if (classForNameNoteCount > 0)
215             {
216                 System.out.println("Note: there were " + classForNameNoteCount +
217                                    " class casts of dynamically created class instances.");
218                 System.out.println(" You might consider explicitly keeping the mentioned classes and/or");
219                 System.out.println(" their implementations (using '-keep').");
220             }
221
222             int getmemberNoteCount = getMemberNotePrinter.getWarningCount();
223             if (getmemberNoteCount > 0)
224             {
225                 System.out.println("Note: there were " + getmemberNoteCount +
226                                    " accesses to class members by means of introspection.");
227                 System.out.println(" You should consider explicitly keeping the mentioned class members");
228                 System.out.println(" (using '-keep' or '-keepclassmembers').");
229             }
230         }
231
232         // Print out a summary of the warnings, if necessary.
233
if (configuration.warn)
234         {
235             int hierarchyWarningCount = hierarchyWarningPrinter.getWarningCount();
236             if (hierarchyWarningCount > 0)
237             {
238                 System.err.println("Warning: there were " + hierarchyWarningCount +
239                                    " unresolved references to superclasses or interfaces.");
240                 System.err.println(" You may need to specify additional library jars (using '-libraryjars'),");
241                 System.err.println(" or perhaps the '-dontskipnonpubliclibraryclasses' option.");
242             }
243
244             int referenceWarningCount = referenceWarningPrinter.getWarningCount();
245             if (referenceWarningCount > 0)
246             {
247                 System.err.println("Warning: there were " + referenceWarningCount +
248                                    " unresolved references to program class members.");
249                 System.err.println(" Your input classes appear to be inconsistent.");
250                 System.err.println(" You may need to recompile them and try again.");
251                 System.err.println(" Alternatively, you may have to specify the options ");
252                 System.err.println(" '-dontskipnonpubliclibraryclasses' and/or");
253                 System.err.println(" '-dontskipnonpubliclibraryclassmembers'.");
254             }
255
256             if ((hierarchyWarningCount > 0 ||
257                  referenceWarningCount > 0) &&
258                 !configuration.ignoreWarnings)
259             {
260                 throw new IOException JavaDoc("Please correct the above warnings first.");
261             }
262         }
263
264         // Discard unused library classes.
265
if (configuration.verbose)
266         {
267             System.out.println("Ignoring unused library classes...");
268             System.out.println(" Original number of library classes: " + originalLibraryClassPoolSize);
269             System.out.println(" Final number of library classes: " + libraryClassPool.size());
270         }
271     }
272
273
274     /**
275      * Extracts a list of exceptions of classes for which not to print notes,
276      * from the keep configuration.
277      */

278     private ClassNameListMatcher createClassNoteExceptionMatcher(List noteExceptions)
279     {
280         if (noteExceptions != null)
281         {
282             List noteExceptionNames = new ArrayList(noteExceptions.size());
283             for (int index = 0; index < noteExceptions.size(); index++)
284             {
285                 KeepSpecification keepSpecification = (KeepSpecification)noteExceptions.get(index);
286                 if (keepSpecification.markClasses)
287                 {
288                     // If the class itself is being kept, it's ok.
289
String JavaDoc className = keepSpecification.className;
290                     if (className != null)
291                     {
292                         noteExceptionNames.add(className);
293                     }
294
295                     // If all of its extensions are being kept, it's ok too.
296
String JavaDoc extendsClassName = keepSpecification.extendsClassName;
297                     if (extendsClassName != null)
298                     {
299                         noteExceptionNames.add(extendsClassName);
300                     }
301                 }
302             }
303
304             if (noteExceptionNames.size() > 0)
305             {
306                 return new ClassNameListMatcher(noteExceptionNames);
307             }
308         }
309
310         return null;
311     }
312
313
314     /**
315      * Extracts a list of exceptions of field or method names for which not to
316      * print notes, from the keep configuration.
317      */

318     private ClassNameListMatcher createClassMemberNoteExceptionMatcher(List noteExceptions,
319                                                                        boolean isField)
320     {
321         if (noteExceptions != null)
322         {
323             List noteExceptionNames = new ArrayList();
324             for (int index = 0; index < noteExceptions.size(); index++)
325             {
326                 KeepSpecification keepSpecification = (KeepSpecification)noteExceptions.get(index);
327                 List memberSpecifications = isField ?
328                     keepSpecification.fieldSpecifications :
329                     keepSpecification.methodSpecifications;
330
331                 if (memberSpecifications != null)
332                 {
333                     for (int index2 = 0; index2 < memberSpecifications.size(); index2++)
334                     {
335                         MemberSpecification memberSpecification =
336                             (MemberSpecification)memberSpecifications.get(index2);
337
338                         String JavaDoc memberName = memberSpecification.name;
339                         if (memberName != null)
340                         {
341                             noteExceptionNames.add(memberName);
342                         }
343                     }
344                 }
345             }
346
347             if (noteExceptionNames.size() > 0)
348             {
349                 return new ClassNameListMatcher(noteExceptionNames);
350             }
351         }
352
353         return null;
354     }
355 }
356
Popular Tags