Mon, 09 Mar 2009 23:53:41 -0700
Merge
1 /*
2 * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
26 package com.sun.tools.doclets.internal.toolkit.builders;
28 import java.io.*;
29 import java.lang.reflect.*;
30 import java.util.*;
32 import com.sun.javadoc.*;
33 import com.sun.tools.doclets.internal.toolkit.util.*;
34 import com.sun.tools.doclets.internal.toolkit.*;
36 /**
37 * Builds the serialized form.
38 *
39 * This code is not part of an API.
40 * It is implementation that is subject to change.
41 * Do not use it as an API
42 *
43 * @author Jamie Ho
44 * @author Bhavesh Patel (Modified)
45 * @since 1.5
46 */
47 public class SerializedFormBuilder extends AbstractBuilder {
49 /**
50 * The root element of the serialized form XML is {@value}.
51 */
52 public static final String NAME = "SerializedForm";
54 /**
55 * The writer for this builder.
56 */
57 private SerializedFormWriter writer;
59 /**
60 * The writer for serializable fields.
61 */
62 private SerializedFormWriter.SerialFieldWriter fieldWriter;
64 /**
65 * The writer for serializable method documentation.
66 */
67 private SerializedFormWriter.SerialMethodWriter methodWriter;
69 /**
70 * The header for the serial version UID. Save the string
71 * here instead of the properties file because we do not want
72 * this string to be localized.
73 */
74 private static final String SERIAL_VERSION_UID_HEADER = "serialVersionUID:";
76 /**
77 * The current package being documented.
78 */
79 private PackageDoc currentPackage;
81 /**
82 * The current class being documented.
83 */
84 private ClassDoc currentClass;
86 /**
87 * The current member being documented.
88 */
89 protected MemberDoc currentMember;
91 private SerializedFormBuilder(Configuration configuration) {
92 super(configuration);
93 }
95 /**
96 * Construct a new SerializedFormBuilder.
97 * @param configuration the current configuration of the doclet.
98 */
99 public static SerializedFormBuilder getInstance(Configuration configuration) {
100 SerializedFormBuilder builder = new SerializedFormBuilder(configuration);
101 return builder;
102 }
104 /**
105 * Build the serialized form.
106 */
107 public void build() throws IOException {
108 if (! serialClassFoundToDocument(configuration.root.classes())) {
109 //Nothing to document.
110 return;
111 }
112 try {
113 writer = configuration.getWriterFactory().getSerializedFormWriter();
114 if (writer == null) {
115 //Doclet does not support this output.
116 return;
117 }
118 } catch (Exception e) {
119 throw new DocletAbortException();
120 }
121 build(LayoutParser.getInstance(configuration).parseXML(NAME));
122 writer.close();
123 }
125 /**
126 * {@inheritDoc}
127 */
128 public String getName() {
129 return NAME;
130 }
132 /**
133 * Build the serialized form.
134 */
135 public void buildSerializedForm(List<?> elements) throws Exception {
136 build(elements);
137 writer.close();
138 }
140 /**
141 * {@inheritDoc}
142 */
143 public void invokeMethod(String methodName, Class<?>[] paramClasses,
144 Object[] params)
145 throws Exception {
146 if (DEBUG) {
147 configuration.root.printError("DEBUG: " + this.getClass().getName()
148 + "." + methodName);
149 }
150 Method method = this.getClass().getMethod(methodName, paramClasses);
151 method.invoke(this, params);
152 }
154 /**
155 * Build the header.
156 */
157 public void buildHeader() {
158 writer.writeHeader(configuration.getText("doclet.Serialized_Form"));
159 }
161 /**
162 * Build the contents.
163 */
164 public void buildSerializedFormSummaries(List<?> elements) {
165 PackageDoc[] packages = configuration.packages;
166 for (int i = 0; i < packages.length; i++) {
167 currentPackage = packages[i];
168 build(elements);
169 }
170 }
172 /**
173 * Build the package serialized for for the current package being processed.
174 */
175 public void buildPackageSerializedForm(List<?> elements) {
176 String foo = currentPackage.name();
177 ClassDoc[] classes = currentPackage.allClasses(false);
178 if (classes == null || classes.length == 0) {
179 return;
180 }
181 if (!serialInclude(currentPackage)) {
182 return;
183 }
184 if (!serialClassFoundToDocument(classes)) {
185 return;
186 }
187 build(elements);
188 }
190 public void buildPackageHeader() {
191 writer.writePackageHeader(Util.getPackageName(currentPackage));
192 }
194 public void buildClassSerializedForm(List<?> elements) {
195 ClassDoc[] classes = currentPackage.allClasses(false);
196 Arrays.sort(classes);
197 for (int j = 0; j < classes.length; j++) {
198 currentClass = classes[j];
199 fieldWriter = writer.getSerialFieldWriter(currentClass);
200 methodWriter = writer.getSerialMethodWriter(currentClass);
201 if(currentClass.isClass() && currentClass.isSerializable()) {
202 if(!serialClassInclude(currentClass)) {
203 continue;
204 }
205 build(elements);
206 }
207 }
208 }
210 public void buildClassHeader() {
211 writer.writeClassHeader(currentClass);
212 }
214 /**
215 * Build the serial UID information for the given class.
216 */
217 public void buildSerialUIDInfo() {
218 FieldDoc[] fields = currentClass.fields(false);
219 for (int i = 0; i < fields.length; i++) {
220 if (fields[i].name().equals("serialVersionUID") &&
221 fields[i].constantValueExpression() != null) {
222 writer.writeSerialUIDInfo(SERIAL_VERSION_UID_HEADER,
223 fields[i].constantValueExpression());
224 return;
225 }
226 }
227 }
229 /**
230 * Build the footer.
231 */
232 public void buildFooter() {
233 writer.writeFooter();
234 }
236 /**
237 * Return true if the given Doc should be included
238 * in the serialized form.
239 *
240 * @param doc the Doc object to check for serializability.
241 */
242 public static boolean serialInclude(Doc doc) {
243 if (doc == null) {
244 return false;
245 }
246 return doc.isClass() ?
247 serialClassInclude((ClassDoc)doc) :
248 serialDocInclude(doc);
249 }
251 /**
252 * Return true if the given ClassDoc should be included
253 * in the serialized form.
254 *
255 * @param cd the ClassDoc object to check for serializability.
256 */
257 private static boolean serialClassInclude(ClassDoc cd) {
258 if (cd.isEnum()) {
259 return false;
260 }
261 try {
262 cd.superclassType();
263 } catch (NullPointerException e) {
264 //Workaround for null pointer bug in ClassDoc.superclassType().
265 return false;
266 }
267 if (cd.isSerializable()) {
268 if (cd.tags("serial").length > 0) {
269 return serialDocInclude(cd);
270 } else if (cd.isPublic() || cd.isProtected()) {
271 return true;
272 } else {
273 return false;
274 }
275 }
276 return false;
277 }
279 /**
280 * Return true if the given Doc should be included
281 * in the serialized form.
282 *
283 * @param doc the Doc object to check for serializability.
284 */
285 private static boolean serialDocInclude(Doc doc) {
286 if (doc.isEnum()) {
287 return false;
288 }
289 Tag[] serial = doc.tags("serial");
290 if (serial.length > 0) {
291 String serialtext = serial[0].text().toLowerCase();
292 if (serialtext.indexOf("exclude") >= 0) {
293 return false;
294 } else if (serialtext.indexOf("include") >= 0) {
295 return true;
296 }
297 }
298 return true;
299 }
301 /**
302 * Return true if any of the given classes have a @serialinclude tag.
303 *
304 * @param classes the classes to check.
305 * @return true if any of the given classes have a @serialinclude tag.
306 */
307 private boolean serialClassFoundToDocument(ClassDoc[] classes) {
308 for (int i = 0; i < classes.length; i++) {
309 if (serialClassInclude(classes[i])) {
310 return true;
311 }
312 }
313 return false;
314 }
316 /**
317 * Build the method header.
318 */
319 public void buildMethodHeader() {
320 if (currentClass.serializationMethods().length > 0) {
321 methodWriter.writeHeader(
322 configuration.getText("doclet.Serialized_Form_methods"));
323 if (currentClass.isSerializable() && !currentClass.isExternalizable()) {
324 if (currentClass.serializationMethods().length == 0) {
325 methodWriter.writeNoCustomizationMsg(
326 configuration.getText(
327 "doclet.Serializable_no_customization"));
328 }
329 }
330 }
331 }
333 /**
334 * Build the method sub header.
335 */
336 public void buildMethodSubHeader() {
337 methodWriter.writeMemberHeader((MethodDoc) currentMember);
338 }
340 /**
341 * Build the deprecated method description.
342 */
343 public void buildDeprecatedMethodInfo() {
344 methodWriter.writeDeprecatedMemberInfo((MethodDoc) currentMember);
345 }
347 /**
348 * Build method tags.
349 */
350 public void buildMethodDescription() {
351 methodWriter.writeMemberDescription((MethodDoc) currentMember);
352 }
354 /**
355 * Build the method tags.
356 */
357 public void buildMethodTags() {
358 methodWriter.writeMemberTags((MethodDoc) currentMember);
359 MethodDoc method = (MethodDoc)currentMember;
360 if (method.name().compareTo("writeExternal") == 0
361 && method.tags("serialData").length == 0) {
362 if (configuration.serialwarn) {
363 configuration.getDocletSpecificMsg().warning(
364 currentMember.position(), "doclet.MissingSerialDataTag",
365 method.containingClass().qualifiedName(), method.name());
366 }
367 }
368 }
370 /**
371 * build the information for the method.
372 */
373 public void buildMethodInfo(List<?> elements) {
374 if(configuration.nocomment){
375 return;
376 }
377 build(elements);
378 }
380 /**
381 * Build the method footer.
382 */
383 public void buildMethodFooter() {
384 methodWriter.writeMemberFooter();
385 }
387 /**
388 * Build the field header.
389 */
390 public void buildFieldHeader() {
391 if (currentClass.serializableFields().length > 0) {
392 buildFieldSerializationOverview(currentClass);
393 fieldWriter.writeHeader(configuration.getText(
394 "doclet.Serialized_Form_fields"));
395 }
396 }
398 /**
399 * If possible, build the serialization overview for the given
400 * class.
401 *
402 * @param classDoc the class to print the overview for.
403 */
404 public void buildFieldSerializationOverview(ClassDoc classDoc) {
405 if (classDoc.definesSerializableFields()) {
406 FieldDoc serialPersistentField =
407 Util.asList(classDoc.serializableFields()).get(0);
408 // Check to see if there are inline comments, tags or deprecation
409 // information to be printed.
410 if (fieldWriter.shouldPrintOverview(serialPersistentField)) {
411 fieldWriter.writeHeader(
412 configuration.getText("doclet.Serialized_Form_class"));
413 fieldWriter.writeMemberDeprecatedInfo(serialPersistentField);
414 if (!configuration.nocomment) {
415 fieldWriter.writeMemberDescription(serialPersistentField);
416 fieldWriter.writeMemberTags(serialPersistentField);
417 }
418 // Footer required to close the definition list tag
419 // for serialization overview.
420 fieldWriter.writeFooter(
421 configuration.getText("doclet.Serialized_Form_class"));
422 }
423 }
424 }
426 /**
427 * Build the field sub header.
428 */
429 public void buildFieldSubHeader() {
430 if (! currentClass.definesSerializableFields() ){
431 FieldDoc field = (FieldDoc) currentMember;
432 fieldWriter.writeMemberHeader(field.type().asClassDoc(),
433 field.type().typeName(), field.type().dimension(), field.name());
434 }
435 }
437 /**
438 * Build the field deprecation information.
439 */
440 public void buildFieldDeprecationInfo() {
441 if (!currentClass.definesSerializableFields()) {
442 FieldDoc field = (FieldDoc)currentMember;
443 fieldWriter.writeMemberDeprecatedInfo(field);
444 }
445 }
447 /**
448 * Build the field information.
449 */
450 public void buildFieldInfo() {
451 if(configuration.nocomment){
452 return;
453 }
454 FieldDoc field = (FieldDoc)currentMember;
455 ClassDoc cd = field.containingClass();
456 if (cd.definesSerializableFields()) {
457 // Process Serializable Fields specified as array of
458 // ObjectStreamFields. Print a member for each serialField tag.
459 // (There should be one serialField tag per ObjectStreamField
460 // element.)
461 SerialFieldTag[] tags = field.serialFieldTags();
462 Arrays.sort(tags);
463 for (int i = 0; i < tags.length; i++) {
464 fieldWriter.writeMemberHeader(tags[i].fieldTypeDoc(),
465 tags[i].fieldType(), "", tags[i].fieldName());
466 fieldWriter.writeMemberDescription(tags[i]);
468 }
469 } else {
471 // Process default Serializable field.
472 if ((field.tags("serial").length == 0) && ! field.isSynthetic()
473 && configuration.serialwarn) {
474 configuration.message.warning(field.position(),
475 "doclet.MissingSerialTag", cd.qualifiedName(),
476 field.name());
477 }
478 fieldWriter.writeMemberDescription(field);
479 fieldWriter.writeMemberTags(field);
480 }
481 }
483 /**
484 * Build the field sub footer.
485 */
486 public void buildFieldSubFooter() {
487 if (! currentClass.definesSerializableFields()) {
488 fieldWriter.writeMemberFooter();
489 }
490 }
492 /**
493 * Build the summaries for the methods that belong to the given
494 * class.
495 */
496 public void buildSerializableMethods(List<?> elements) {
497 MemberDoc[] members = currentClass.serializationMethods();
498 if (members.length > 0) {
499 for (int i = 0; i < members.length; i++) {
500 currentMember = members[i];
501 build(elements);
502 }
503 }
504 }
506 /**
507 * Build the summaries for the fields that belong to the given
508 * class.
509 */
510 public void buildSerializableFields(List<?> elements) {
511 MemberDoc[] members = currentClass.serializableFields();
512 if (members.length > 0) {
513 for (int i = 0; i < members.length; i++) {
514 currentMember = members[i];
515 build(elements);
516 }
517 }
518 }
519 }