Fri, 18 Jun 2010 21:13:56 -0700
6961178: Allow doclet.xml to contain XML attributes
Reviewed-by: bpatel
1 /*
2 * Copyright (c) 2003, 2009, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.tools.doclets.internal.toolkit.builders;
28 import java.io.*;
29 import java.util.*;
31 import com.sun.javadoc.*;
32 import com.sun.tools.doclets.internal.toolkit.util.*;
33 import com.sun.tools.doclets.internal.toolkit.*;
35 /**
36 * Builds the serialized form.
37 *
38 * This code is not part of an API.
39 * It is implementation that is subject to change.
40 * Do not use it as an API
41 *
42 * @author Jamie Ho
43 * @author Bhavesh Patel (Modified)
44 * @since 1.5
45 */
46 public class SerializedFormBuilder extends AbstractBuilder {
48 /**
49 * The root element of the serialized form XML is {@value}.
50 */
51 public static final String NAME = "SerializedForm";
53 /**
54 * The writer for this builder.
55 */
56 private SerializedFormWriter writer;
58 /**
59 * The writer for serializable fields.
60 */
61 private SerializedFormWriter.SerialFieldWriter fieldWriter;
63 /**
64 * The writer for serializable method documentation.
65 */
66 private SerializedFormWriter.SerialMethodWriter methodWriter;
68 /**
69 * The header for the serial version UID. Save the string
70 * here instead of the properties file because we do not want
71 * this string to be localized.
72 */
73 private static final String SERIAL_VERSION_UID_HEADER = "serialVersionUID:";
75 /**
76 * The current package being documented.
77 */
78 private PackageDoc currentPackage;
80 /**
81 * The current class being documented.
82 */
83 private ClassDoc currentClass;
85 /**
86 * The current member being documented.
87 */
88 protected MemberDoc currentMember;
90 private SerializedFormBuilder(Configuration configuration) {
91 super(configuration);
92 }
94 /**
95 * Construct a new SerializedFormBuilder.
96 * @param configuration the current configuration of the doclet.
97 */
98 public static SerializedFormBuilder getInstance(Configuration configuration) {
99 SerializedFormBuilder builder = new SerializedFormBuilder(configuration);
100 return builder;
101 }
103 /**
104 * Build the serialized form.
105 */
106 public void build() throws IOException {
107 if (! serialClassFoundToDocument(configuration.root.classes())) {
108 //Nothing to document.
109 return;
110 }
111 try {
112 writer = configuration.getWriterFactory().getSerializedFormWriter();
113 if (writer == null) {
114 //Doclet does not support this output.
115 return;
116 }
117 } catch (Exception e) {
118 throw new DocletAbortException();
119 }
120 build(LayoutParser.getInstance(configuration).parseXML(NAME));
121 writer.close();
122 }
124 /**
125 * {@inheritDoc}
126 */
127 public String getName() {
128 return NAME;
129 }
131 /**
132 * Build the serialized form.
133 */
134 public void buildSerializedForm(XMLNode node) throws Exception {
135 buildChildren(node);
136 writer.close();
137 }
139 /**
140 * Build the header.
141 */
142 public void buildHeader(XMLNode node) {
143 writer.writeHeader(configuration.getText("doclet.Serialized_Form"));
144 }
146 /**
147 * Build the contents.
148 */
149 public void buildSerializedFormSummaries(XMLNode node) {
150 PackageDoc[] packages = configuration.packages;
151 for (int i = 0; i < packages.length; i++) {
152 currentPackage = packages[i];
153 buildChildren(node);
154 }
155 }
157 /**
158 * Build the package serialized for for the current package being processed.
159 */
160 public void buildPackageSerializedForm(XMLNode node) {
161 String foo = currentPackage.name();
162 ClassDoc[] classes = currentPackage.allClasses(false);
163 if (classes == null || classes.length == 0) {
164 return;
165 }
166 if (!serialInclude(currentPackage)) {
167 return;
168 }
169 if (!serialClassFoundToDocument(classes)) {
170 return;
171 }
172 buildChildren(node);
173 }
175 public void buildPackageHeader(XMLNode node) {
176 writer.writePackageHeader(Util.getPackageName(currentPackage));
177 }
179 public void buildClassSerializedForm(XMLNode node) {
180 ClassDoc[] classes = currentPackage.allClasses(false);
181 Arrays.sort(classes);
182 for (int j = 0; j < classes.length; j++) {
183 currentClass = classes[j];
184 fieldWriter = writer.getSerialFieldWriter(currentClass);
185 methodWriter = writer.getSerialMethodWriter(currentClass);
186 if(currentClass.isClass() && currentClass.isSerializable()) {
187 if(!serialClassInclude(currentClass)) {
188 continue;
189 }
190 buildChildren(node);
191 }
192 }
193 }
195 public void buildClassHeader(XMLNode node) {
196 writer.writeClassHeader(currentClass);
197 }
199 /**
200 * Build the serial UID information for the given class.
201 */
202 public void buildSerialUIDInfo(XMLNode node) {
203 FieldDoc[] fields = currentClass.fields(false);
204 for (int i = 0; i < fields.length; i++) {
205 if (fields[i].name().equals("serialVersionUID") &&
206 fields[i].constantValueExpression() != null) {
207 writer.writeSerialUIDInfo(SERIAL_VERSION_UID_HEADER,
208 fields[i].constantValueExpression());
209 return;
210 }
211 }
212 }
214 /**
215 * Build the footer.
216 */
217 public void buildFooter(XMLNode node) {
218 writer.writeFooter();
219 }
221 /**
222 * Return true if the given Doc should be included
223 * in the serialized form.
224 *
225 * @param doc the Doc object to check for serializability.
226 */
227 public static boolean serialInclude(Doc doc) {
228 if (doc == null) {
229 return false;
230 }
231 return doc.isClass() ?
232 serialClassInclude((ClassDoc)doc) :
233 serialDocInclude(doc);
234 }
236 /**
237 * Return true if the given ClassDoc should be included
238 * in the serialized form.
239 *
240 * @param cd the ClassDoc object to check for serializability.
241 */
242 private static boolean serialClassInclude(ClassDoc cd) {
243 if (cd.isEnum()) {
244 return false;
245 }
246 try {
247 cd.superclassType();
248 } catch (NullPointerException e) {
249 //Workaround for null pointer bug in ClassDoc.superclassType().
250 return false;
251 }
252 if (cd.isSerializable()) {
253 if (cd.tags("serial").length > 0) {
254 return serialDocInclude(cd);
255 } else if (cd.isPublic() || cd.isProtected()) {
256 return true;
257 } else {
258 return false;
259 }
260 }
261 return false;
262 }
264 /**
265 * Return true if the given Doc should be included
266 * in the serialized form.
267 *
268 * @param doc the Doc object to check for serializability.
269 */
270 private static boolean serialDocInclude(Doc doc) {
271 if (doc.isEnum()) {
272 return false;
273 }
274 Tag[] serial = doc.tags("serial");
275 if (serial.length > 0) {
276 String serialtext = serial[0].text().toLowerCase();
277 if (serialtext.indexOf("exclude") >= 0) {
278 return false;
279 } else if (serialtext.indexOf("include") >= 0) {
280 return true;
281 }
282 }
283 return true;
284 }
286 /**
287 * Return true if any of the given classes have a @serialinclude tag.
288 *
289 * @param classes the classes to check.
290 * @return true if any of the given classes have a @serialinclude tag.
291 */
292 private boolean serialClassFoundToDocument(ClassDoc[] classes) {
293 for (int i = 0; i < classes.length; i++) {
294 if (serialClassInclude(classes[i])) {
295 return true;
296 }
297 }
298 return false;
299 }
301 /**
302 * Build the method header.
303 */
304 public void buildMethodHeader(XMLNode node) {
305 if (currentClass.serializationMethods().length > 0) {
306 methodWriter.writeHeader(
307 configuration.getText("doclet.Serialized_Form_methods"));
308 if (currentClass.isSerializable() && !currentClass.isExternalizable()) {
309 if (currentClass.serializationMethods().length == 0) {
310 methodWriter.writeNoCustomizationMsg(
311 configuration.getText(
312 "doclet.Serializable_no_customization"));
313 }
314 }
315 }
316 }
318 /**
319 * Build the method sub header.
320 */
321 public void buildMethodSubHeader(XMLNode node) {
322 methodWriter.writeMemberHeader((MethodDoc) currentMember);
323 }
325 /**
326 * Build the deprecated method description.
327 */
328 public void buildDeprecatedMethodInfo(XMLNode node) {
329 methodWriter.writeDeprecatedMemberInfo((MethodDoc) currentMember);
330 }
332 /**
333 * Build method tags.
334 */
335 public void buildMethodDescription(XMLNode node) {
336 methodWriter.writeMemberDescription((MethodDoc) currentMember);
337 }
339 /**
340 * Build the method tags.
341 */
342 public void buildMethodTags(XMLNode node) {
343 methodWriter.writeMemberTags((MethodDoc) currentMember);
344 MethodDoc method = (MethodDoc)currentMember;
345 if (method.name().compareTo("writeExternal") == 0
346 && method.tags("serialData").length == 0) {
347 if (configuration.serialwarn) {
348 configuration.getDocletSpecificMsg().warning(
349 currentMember.position(), "doclet.MissingSerialDataTag",
350 method.containingClass().qualifiedName(), method.name());
351 }
352 }
353 }
355 /**
356 * build the information for the method.
357 */
358 public void buildMethodInfo(XMLNode node) {
359 if(configuration.nocomment){
360 return;
361 }
362 buildChildren(node);
363 }
365 /**
366 * Build the method footer.
367 */
368 public void buildMethodFooter(XMLNode node) {
369 methodWriter.writeMemberFooter();
370 }
372 /**
373 * Build the field header.
374 */
375 public void buildFieldHeader(XMLNode node) {
376 if (currentClass.serializableFields().length > 0) {
377 buildFieldSerializationOverview(currentClass);
378 fieldWriter.writeHeader(configuration.getText(
379 "doclet.Serialized_Form_fields"));
380 }
381 }
383 /**
384 * If possible, build the serialization overview for the given
385 * class.
386 *
387 * @param classDoc the class to print the overview for.
388 */
389 public void buildFieldSerializationOverview(ClassDoc classDoc) {
390 if (classDoc.definesSerializableFields()) {
391 FieldDoc serialPersistentField =
392 Util.asList(classDoc.serializableFields()).get(0);
393 // Check to see if there are inline comments, tags or deprecation
394 // information to be printed.
395 if (fieldWriter.shouldPrintOverview(serialPersistentField)) {
396 fieldWriter.writeHeader(
397 configuration.getText("doclet.Serialized_Form_class"));
398 fieldWriter.writeMemberDeprecatedInfo(serialPersistentField);
399 if (!configuration.nocomment) {
400 fieldWriter.writeMemberDescription(serialPersistentField);
401 fieldWriter.writeMemberTags(serialPersistentField);
402 }
403 // Footer required to close the definition list tag
404 // for serialization overview.
405 fieldWriter.writeFooter(
406 configuration.getText("doclet.Serialized_Form_class"));
407 }
408 }
409 }
411 /**
412 * Build the field sub header.
413 */
414 public void buildFieldSubHeader(XMLNode node) {
415 if (! currentClass.definesSerializableFields() ){
416 FieldDoc field = (FieldDoc) currentMember;
417 fieldWriter.writeMemberHeader(field.type().asClassDoc(),
418 field.type().typeName(), field.type().dimension(), field.name());
419 }
420 }
422 /**
423 * Build the field deprecation information.
424 */
425 public void buildFieldDeprecationInfo(XMLNode node) {
426 if (!currentClass.definesSerializableFields()) {
427 FieldDoc field = (FieldDoc)currentMember;
428 fieldWriter.writeMemberDeprecatedInfo(field);
429 }
430 }
432 /**
433 * Build the field information.
434 */
435 public void buildFieldInfo(XMLNode node) {
436 if(configuration.nocomment){
437 return;
438 }
439 FieldDoc field = (FieldDoc)currentMember;
440 ClassDoc cd = field.containingClass();
441 if (cd.definesSerializableFields()) {
442 // Process Serializable Fields specified as array of
443 // ObjectStreamFields. Print a member for each serialField tag.
444 // (There should be one serialField tag per ObjectStreamField
445 // element.)
446 SerialFieldTag[] tags = field.serialFieldTags();
447 Arrays.sort(tags);
448 for (int i = 0; i < tags.length; i++) {
449 fieldWriter.writeMemberHeader(tags[i].fieldTypeDoc(),
450 tags[i].fieldType(), "", tags[i].fieldName());
451 fieldWriter.writeMemberDescription(tags[i]);
453 }
454 } else {
456 // Process default Serializable field.
457 if ((field.tags("serial").length == 0) && ! field.isSynthetic()
458 && configuration.serialwarn) {
459 configuration.message.warning(field.position(),
460 "doclet.MissingSerialTag", cd.qualifiedName(),
461 field.name());
462 }
463 fieldWriter.writeMemberDescription(field);
464 fieldWriter.writeMemberTags(field);
465 }
466 }
468 /**
469 * Build the field sub footer.
470 */
471 public void buildFieldSubFooter(XMLNode node) {
472 if (! currentClass.definesSerializableFields()) {
473 fieldWriter.writeMemberFooter();
474 }
475 }
477 /**
478 * Build the summaries for the methods that belong to the given
479 * class.
480 */
481 public void buildSerializableMethods(XMLNode node) {
482 MemberDoc[] members = currentClass.serializationMethods();
483 if (members.length > 0) {
484 for (int i = 0; i < members.length; i++) {
485 currentMember = members[i];
486 buildChildren(node);
487 }
488 }
489 }
491 /**
492 * Build the summaries for the fields that belong to the given
493 * class.
494 */
495 public void buildSerializableFields(XMLNode node) {
496 MemberDoc[] members = currentClass.serializableFields();
497 if (members.length > 0) {
498 for (int i = 0; i < members.length; i++) {
499 currentMember = members[i];
500 buildChildren(node);
501 }
502 }
503 }
504 }