View Javadoc

1   /*
2    * Copyright 2001-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.geronimo.ews.jaxrpcmapping;
18  
19  import org.apache.axis.Constants;
20  import org.apache.axis.utils.JavaUtils;
21  import org.apache.axis.utils.Messages;
22  import org.apache.axis.wsdl.symbolTable.ElementDecl;
23  import org.apache.axis.wsdl.symbolTable.SchemaUtils;
24  import org.apache.axis.wsdl.symbolTable.TypeEntry;
25  import org.apache.axis.wsdl.toJava.JavaWriter;
26  import org.apache.axis.wsdl.toJava.Utils;
27  import org.w3c.dom.Node;
28  
29  import javax.xml.namespace.QName;
30  import java.io.IOException;
31  import java.io.PrintWriter;
32  import java.util.ArrayList;
33  import java.util.Iterator;
34  import java.util.Vector;
35  
36  /***
37   * This is Wsdl2java's Complex Type Writer.  It writes the <typeName>.java file.
38   *
39   * @author Ias (iasandcb@tmax.co.kr)
40   * @deprecated no more used by J2eeGeneratorFactory
41   */
42  public class J2eeBeanWriter extends J2eeClassWriter {
43      private TypeEntry type;
44      private Vector elements;
45      private Vector attributes;
46      private TypeEntry extendType;
47      protected J2eeBeanHelperWriter helper;
48      protected Vector names = new Vector(); // even indices: types, odd: vars
49      protected ArrayList simpleValueTypes = new ArrayList();  // name of type of simple value
50      protected PrintWriter pw;
51  
52      // The following fields can be set by extended classes
53      // to control processing
54      protected boolean enableDefaultConstructor = true;
55      protected boolean enableFullConstructor = false;
56      protected boolean enableSimpleConstructors = false;
57      protected boolean enableToString = false;
58      protected boolean enableSetters = true;
59      protected boolean enableGetters = true;
60      protected boolean enableEquals = true;
61      protected boolean enableHashCode = true;
62      protected boolean enableMemberFields = true;
63  
64      protected boolean isAny = false;
65  
66      /***
67       * Constructor.
68       *
69       * @param emitter
70       * @param type       The type representing this class
71       * @param elements   Vector containing the Type and name of each property
72       * @param extendType The type representing the extended class (or null)
73       * @param attributes Vector containing the attribute types and names
74       * @param helper     Helper class writer
75       */
76      protected J2eeBeanWriter(J2eeEmitter emitter,
77                               TypeEntry type,
78                               Vector elements,
79                               TypeEntry extendType,
80                               Vector attributes,
81                               JavaWriter helper) {
82          super(emitter, emitter.getJaxRpcMapper().getJavaType(type.getQName()), "complexType");
83          this.type = type;
84          this.elements = elements;
85          this.attributes = attributes;
86          this.extendType = extendType;
87          this.helper = (J2eeBeanHelperWriter) helper;
88          if (type.isSimpleType()) {
89              enableSimpleConstructors = true;
90              enableToString = true;
91          } else {
92              // is this a complex type that is derived from other types
93              // by restriction?  if so, do not emit instance variables
94              // or accessor/mutator pairs as those are inherited from
95              // the super type, which must be non-null.
96              if (null != extendType
97                      && null != SchemaUtils.getComplexElementRestrictionBase(type.getNode(),
98                              emitter.getSymbolTable())) {
99                  enableMemberFields = false;
100                 enableGetters = false;
101                 enableSetters = false;
102                 enableEquals = false;
103                 enableHashCode = false;
104             }
105         }
106     } // ctor
107 
108     /***
109      * Generate the binding for the given complex type.
110      */
111     protected void writeFileBody(PrintWriter pw) throws IOException {
112         this.pw = pw;
113 
114         // Populate Names Vector with the names and types of the members.
115         // The write methods use the names vector whenever they need to get
116         // a member name or type. Moved to implements callback in order 
117         // to set any interface
118         // preprocess();
119 
120         // Write Member Fields
121         if (enableMemberFields) {
122             writeMemberFields();
123         }
124 
125         // Write the default constructor
126         if (enableDefaultConstructor) {
127             writeDefaultConstructor();
128         }
129 
130         // Write Full Constructor
131         if (enableFullConstructor) {
132             writeFullConstructor();
133         }
134 
135         // Write SimpleConstructors
136         if (enableSimpleConstructors) {
137             writeSimpleConstructors();
138         }
139 
140         // Write ToString method
141         if (enableToString) {
142             writeToStringMethod();
143         }
144 
145         // Write accessor methods
146         writeAccessMethods();
147 
148         // Write general purpose equals and hashCode methods
149         if (enableEquals) {
150             writeEqualsMethod();
151         }
152         if (enableHashCode) {
153             writeHashCodeMethod();
154         }
155 
156         // Write the meta data into a Helper class or
157         // embed it in the bean class
158         if (!emitter.isHelperWanted()) {
159             // Write the helper info into the bean class
160             helper.setPrintWriter(pw);
161         }
162         helper.generate();
163     } // writeFileBody
164 
165     /***
166      * Builds the names String vector.
167      * The even indices are the java class names of the
168      * member fields.  The odd indices are the member variable
169      * names.
170      * Also sets the simpleValueType variable to the
171      * java class name of the simple value if this bean represents
172      * a simple type
173      */
174     protected void preprocess() {
175         // Add element names
176         if (elements != null) {
177             for (int i = 0; i < elements.size(); i++) {
178                 ElementDecl elem = (ElementDecl) elements.get(i);
179                 String typeName = elem.getType().getName();
180                 String variableName;
181                 if (elem.getAnyElement()) {
182                     typeName = "org.apache.axis.message.MessageElement []";
183                     variableName = Constants.ANYCONTENT;
184                     isAny = true;
185                 } else {
186                     variableName = elem.getName();
187                 }
188                 names.add(typeName);
189                 names.add(variableName);
190                 if (type.isSimpleType() &&
191                         (variableName.endsWith("Value") || variableName.equals("value"))) {
192                     simpleValueTypes.add(typeName);
193                 }
194             }
195         }
196         // Add attribute names
197         if (attributes != null) {
198             for (int i = 0; i < attributes.size(); i += 2) {
199                 String typeName = ((TypeEntry) attributes.get(i)).getName();
200                 QName xmlName = (QName) attributes.get(i + 1);
201                 String variableName =
202                         Utils.xmlNameToJava(xmlName.getLocalPart());
203                 names.add(typeName);
204                 names.add(variableName);
205                 if (type.isSimpleType() &&
206                         (variableName.endsWith("Value") || variableName.equals("value"))) {
207                     simpleValueTypes.add(typeName);
208                 }
209             }
210         }
211         if (extendType != null && extendType.getDimensions().equals("[]")) {
212             String typeName = extendType.getName();
213             String elemName = extendType.getQName().getLocalPart();
214             String variableName = Utils.xmlNameToJava(elemName);
215             names.add(typeName);
216             names.add(variableName);
217         }
218     }
219 
220     /***
221      * Returns the appropriate extends text
222      *
223      * @return "" or "abstract "
224      */
225     protected String getClassModifiers() {
226         Node node = type.getNode();
227         if (node != null) {
228             if (JavaUtils.isTrueExplicitly(Utils.getAttribute(node, "abstract"))) {
229                 return super.getClassModifiers() + "abstract ";
230             }
231         }
232         return super.getClassModifiers();
233     } // getClassModifiers
234 
235     /***
236      * Returns the appropriate extends text
237      *
238      * @return "" or " extends <class> "
239      */
240     protected String getExtendsText() {
241         // See if this class extends another class
242         String extendsText = "";
243         if (extendType != null && !type.isSimpleType() && extendType.getDimensions().length() == 0) {
244             extendsText = " extends " + extendType.getName() + " ";
245         }
246         return extendsText;
247     }
248 
249     /***
250      * Returns the appropriate implements text
251      *
252      * @return " implements <classes> "
253      */
254     protected String getImplementsText() {
255         // See if this class extends another class
256         String implementsText = " implements java.io.Serializable";
257         if (type.isSimpleType()) {
258             implementsText += ", org.apache.axis.encoding.SimpleType";
259         }
260         
261         // need to call this to find out whether the type contains any elements
262         preprocess();
263         if (isAny) {
264             implementsText += ", org.apache.axis.encoding.AnyContentType";
265         }
266         ;
267         implementsText += " ";
268         return implementsText;
269     }
270 
271     /***
272      * Writes the member fields.
273      */
274     protected void writeMemberFields() {
275         // Define the member element of the bean
276         if (isUnion()) {
277             pw.println("    private java.lang.String value;");
278             return;
279         }
280         for (int i = 0; i < names.size(); i += 2) {
281             String typeName = (String) names.get(i);
282             String variable = (String) names.get(i + 1);
283 
284             // Declare the bean element
285             pw.print("    private " + typeName + " " + variable + ";");
286 
287             // label the attribute fields.
288             if (elements == null || i >= (elements.size() * 2))
289                 pw.println("  // attribute");
290             else
291                 pw.println();
292         }
293         pw.println();
294     }
295 
296     /***
297      * Writes the default constructor.
298      */
299     protected void writeDefaultConstructor() {
300         // Define the default constructor
301         pw.println("    public " + className + "() {");
302         pw.println("    }");
303         pw.println();
304     }
305 
306     /***
307      * Writes the full constructor.
308      * Note that this class is not recommended for
309      * JSR 101 compliant beans, but is provided for
310      * extended classes which may wish to generate a full
311      * constructor.
312      */
313     protected void writeFullConstructor() {
314         if (type.isSimpleType()) {
315             return;
316         }
317         // The constructor needs to consider all extended types
318         Vector extendList = new Vector();
319         extendList.add(type);
320         TypeEntry parent = extendType;
321         while (parent != null) {
322             extendList.add(parent);
323             parent = SchemaUtils.getComplexElementExtensionBase(parent.getNode(),
324                     emitter.getSymbolTable());
325         }
326 
327         // Now generate a list of names and types starting with
328         // the oldest parent.  (Attrs are considered before elements).
329         Vector paramTypes = new Vector();
330         Vector paramNames = new Vector();
331         for (int i = extendList.size() - 1; i >= 0; i--) {
332             TypeEntry te = (TypeEntry) extendList.elementAt(i);
333 
334             // The names of the inherited parms are mangled
335             // in case they interfere with local parms.
336             String mangle = "";
337             if (i > 0) {
338                 mangle = "_" +
339                         Utils.xmlNameToJava(te.getQName().getLocalPart()) +
340                         "_";
341             }
342             // Process the attributes
343             Vector attributes = SchemaUtils.getContainedAttributeTypes(te.getNode(), emitter.getSymbolTable());
344             if (attributes != null) {
345                 for (int j = 0; j < attributes.size(); j += 2) {
346                     paramTypes.add(((TypeEntry) attributes.get(j)).getName());
347                     String name = ((QName) attributes.get(j + 1)).getLocalPart();
348                     paramNames.add(mangle + Utils.xmlNameToJava(name));
349                 }
350             }
351             // Process the elements
352             Vector elements = SchemaUtils.getContainedElementDeclarations(te.getNode(), emitter.getSymbolTable());
353             if (elements != null) {
354                 for (int j = 0; j < elements.size(); j++) {
355                     ElementDecl elem = (ElementDecl) elements.get(j);
356                     paramTypes.add(elem.getType().getName());
357                     paramNames.add(mangle + elem.getName());
358                 }
359             }
360         }
361         // Set the index where the local params start
362         int localParams = paramTypes.size() - names.size() / 2;
363 
364 
365         // Now write the constructor signature
366         if (paramTypes.size() > 0) {
367             pw.println("    public " + className + "(");
368             for (int i = 0; i < paramTypes.size(); i++) {
369                 pw.print("           " + paramTypes.elementAt(i) +
370                         " " + paramNames.elementAt(i));
371                 if ((i + 1) < paramTypes.size()) {
372                     pw.println(",");
373                 } else {
374                     pw.println(") {");
375                 }
376             }
377 
378             // Call the extended constructor to set inherited fields
379             if (extendType != null && localParams > 0) {
380                 pw.println("        super(");
381                 for (int j = 0; j < localParams; j++) {
382                     pw.print("            " + paramNames.elementAt(j));
383                     if ((j + 1) < localParams) {
384                         pw.println(",");
385                     } else {
386                         pw.println(");");
387                     }
388                 }
389             }
390             // Set local fields directly
391             for (int j = localParams; j < paramNames.size(); j++) {
392                 pw.println("        this." + paramNames.elementAt(j) +
393                         " = " + paramNames.elementAt(j) + ";");
394             }
395             pw.println("    }");
396             pw.println();
397         }
398     }
399 
400     /***
401      * Writes the constructors for SimpleTypes.
402      * Writes a constructor accepting a string and
403      * a constructor accepting the simple java type.
404      */
405     protected void writeSimpleConstructors() {
406         // If this is a simple type,need to emit a string
407         // constructor and a value construtor.
408         if (simpleValueTypes.size() == 0) {
409             return;
410         }
411         pw.println("    // " + Messages.getMessage("needStringCtor"));
412         if (isUnion() || simpleValueTypes.get(0).equals("java.lang.String")) {
413             pw.println("    public " + className + "(java.lang.String value) {");
414             pw.println("        this.value = value;");
415             pw.println("    }");
416             for (Iterator iterator = simpleValueTypes.iterator();
417                  iterator.hasNext();) {
418                 String typeName = (String) iterator.next();
419                 if (typeName.equals("java.lang.String")) {
420                     continue;
421                 }
422                 pw.println("    public " + className + "(" + typeName + " value) {");
423                 pw.println("        setValue(value);");
424                 pw.println("    }");
425                 pw.println();
426             }
427         } else if (simpleValueTypes.size() == 1) {
428             pw.println("    public " + className + "(" + simpleValueTypes.get(0) + " value) {");
429             pw.println("        this.value = value;");
430             pw.println("    }");
431             pw.println("    public " + className + "(java.lang.String value) {");
432             writeSimpleTypeGetter((String) simpleValueTypes.get(0), null, "this.value =");
433             pw.println("    }");
434             pw.println();
435         }
436     }
437 
438     protected void writeSimpleTypeGetter(String simpleValueType, String name, String returnString) {
439         // Make sure we wrap base types with its Object type
440         String wrapper = JavaUtils.getWrapper(simpleValueType);
441         if (wrapper != null) {
442             pw.println("        " + returnString + " new " + wrapper +
443                     "(value)." + simpleValueType + "Value();");
444         } else {
445             if (simpleValueType.equals("byte[]")) {
446                 pw.println("        " + returnString + " org.apache.axis.types.HexBinary.decode(value);");
447             } else if (simpleValueType.equals("org.apache.axis.types.URI")) {
448                 pw.println("        try {");
449                 pw.println("            " + returnString + " new org.apache.axis.types.URI(value);");
450                 pw.println("        }");
451                 pw.println("        catch (org.apache.axis.types.URI.MalformedURIException mue) {");
452                 pw.println("            " + returnString + " new org.apache.axis.types.URI();");
453                 pw.println("       }");
454             } else if (simpleValueType.equals("java.util.Date")) {
455                 pw.println("        try {");
456                 pw.println("            " + returnString + " (java.text.DateFormat.getDateTimeInstance()).parse(value);");
457                 pw.println("        }");
458                 pw.println("        catch (java.text.ParseException e){");
459                 pw.println("            throw new java.lang.RuntimeException(e.toString());");
460                 pw.println("        }");
461             } else if (simpleValueType.equals("java.util.Calendar")) {
462                 pw.println("        java.util.Calendar cal =");
463                 pw.println("            (java.util.Calendar) new org.apache.axis.encoding.ser.CalendarDeserializer(");
464                 pw.println("                java.lang.String.class, org.apache.axis.Constants.XSD_STRING).makeValue(value);");
465                 pw.println("        " + returnString + " cal;");
466             } else {
467                 pw.println("        " + returnString + " new " +
468                         simpleValueType + "(value);");
469             }
470         }
471     }
472 
473     private boolean isUnion() {
474         return this.simpleValueTypes.size() > 1;
475     }
476 
477     /***
478      * Writes the toString method
479      * Currently the toString method is only written for
480      * simpleTypes.
481      */
482     protected void writeToStringMethod() {
483         // If this is a simple type, emit a toString
484         if (simpleValueTypes.size() == 0) {
485             return;
486         }
487         pw.println("    // " + Messages.getMessage("needToString"));
488         pw.println("    public java.lang.String toString() {");
489         if (isUnion() || simpleValueTypes.get(0).equals("java.lang.String")) {
490             pw.println("        return value;");
491         } else {
492             String wrapper = JavaUtils.getWrapper((String) simpleValueTypes.get(0));
493             if (wrapper != null) {
494                 pw.println("        return new " + wrapper + "(value).toString();");
495             } else {
496                 if (simpleValueTypes.get(0).equals("byte[]")) {
497                     pw.println("        return value == null ? null : org.apache.axis.types.HexBinary.encode(value);");
498                 } else {
499                     pw.println("        return value == null ? null : value.toString();");
500                 }
501             }
502         }
503         pw.println("    }");
504         pw.println();
505     }
506 
507     protected void writeSimpleTypeSetter(String simpleValueType) {
508         String wrapper = JavaUtils.getWrapper(simpleValueType);
509         if (wrapper != null) {
510             pw.println("        this.value = new " + wrapper + "(value).toString();");
511         } else {
512             if (simpleValueType.equals("byte[]")) {
513                 pw.println("        this.value = value == null ? null : org.apache.axis.types.HexBinary.encode(value);");
514             } else if (simpleValueType.equals("java.util.Calendar")) {
515                 pw.println("        this.value = value == null ? null : new org.apache.axis.encoding.ser.CalendarSerializer().getValueAsString(value, null);");
516             } else {
517                 pw.println("        this.value = value == null ? null : value.toString();");
518             }
519         }
520     }
521 
522     /***
523      * Writes the setter and getter methods
524      */
525     protected void writeAccessMethods() {
526         int j = 0;
527         // Define getters and setters for the bean elements
528         for (int i = 0; i < names.size(); i += 2, j++) {
529             String typeName = (String) names.get(i);
530             String name = (String) names.get(i + 1);
531             String capName = Utils.capitalizeFirstChar(name);
532             String get = "get";
533             if (typeName.equals("boolean"))
534                 get = "is";
535             if (enableGetters) {
536                 pw.println("    public " + typeName + " " +
537                         get + capName + "() {");
538                 if (isUnion()) {
539                     writeSimpleTypeGetter(typeName, name, "return");
540                 } else {
541                     pw.println("        return " + name + ";");
542                 }
543                 pw.println("    }");
544                 pw.println();
545             }
546             if (enableSetters) {
547                 if (isUnion()) {
548                     pw.println("    public void setValue(" +
549                             typeName + " value) {");
550                     writeSimpleTypeSetter(typeName);
551                 } else {
552                     pw.println("    public void set" + capName + "(" +
553                             typeName + " " + name + ") {");
554                     pw.println("        this." + name + " = " + name + ";");
555                 }
556                 pw.println("    }");
557                 pw.println();
558             }
559 
560             // If this is a special collection type, insert extra
561             // java code so that the serializer/deserializer can recognize
562             // the class.  This is not JAX-RPC, and will be replaced with
563             // compliant code when JAX-RPC determines how to deal with this case.
564             // These signatures comply with Bean Indexed Properties which seems
565             // like the reasonable approach to take for collection types.
566             // (It may be more efficient to handle this with an ArrayList...but
567             // for the initial support it was easier to use an actual array.)
568             if (elements != null && j < elements.size()) {
569                 ElementDecl elem = (ElementDecl) elements.get(j);
570                 if (elem.getType().getQName().getLocalPart().indexOf("[") > 0) {
571                     String compName = typeName.substring(0, typeName.lastIndexOf("["));
572                     if (enableGetters) {
573                         pw.println("    public " + compName + " " + get + capName +
574                                 "(int i) {");
575                         pw.println("        return " + name + "[i];");
576                         pw.println("    }");
577                         pw.println();
578                     }
579                     if (enableSetters) {
580                         pw.println("    public void set" + capName + "(int i, " +
581                                 compName + " value) {");
582                         // According to the section 7.2 of the JavaBeans
583                         // specification, the indexed setter should not
584                         // establish or grow the array.  Thus the following
585                         // code is not generated for compliance purposes.
586                         /*
587                         int bracketIndex = typeName.indexOf("[");
588                         String newingName = typeName.substring(0, bracketIndex + 1);
589                         String newingSuffix = typeName.substring(bracketIndex + 1);
590 
591                         pw.println("        if (this." + name + " == null ||");
592                         pw.println("            this." + name + ".length <= i) {");
593                         pw.println("            " + typeName + " a = new " +
594                                    newingName + "i + 1" + newingSuffix + ";");
595                         pw.println("            if (this." + name + " != null) {");
596                         pw.println("                for(int j = 0; j < this." + name +
597                                    ".length; j++)");
598                         pw.println("                    a[j] = this." + name + "[j];");
599                         pw.println("            }");
600                         pw.println("            this." + name + " = a;");
601                         pw.println("        }");
602                         */
603                         pw.println("        this." + name + "[i] = value;");
604                         pw.println("    }");
605                         pw.println();
606                     }
607                 }
608             }
609         }
610     }
611 
612     /***
613      * Writes a general purpose equals method
614      */
615     protected void writeEqualsMethod() {
616         // The __equalsCalc field and synchronized method are necessary
617         // in case the object has direct or indirect references to itself.
618         pw.println("    private java.lang.Object __equalsCalc = null;");
619         pw.println("    public synchronized boolean equals(java.lang.Object obj) {");
620 
621         // First do the general comparison checks
622         pw.println("        if (!(obj instanceof " + className + ")) return false;");
623         pw.println("        " + className + " other = (" + className + ") obj;");
624         pw.println("        if (obj == null) return false;");
625         pw.println("        if (this == obj) return true;");
626 
627         // Have we been here before ? return true if yes otherwise false
628         pw.println("        if (__equalsCalc != null) {");
629         pw.println("            return (__equalsCalc == obj);");
630         pw.println("        }");
631         pw.println("        __equalsCalc = obj;");
632 
633         // Before checking the elements, check equality of the super class
634         String truth = "true";
635         if (extendType != null && !type.isSimpleType()) {
636             truth = "super.equals(obj)";
637         }
638         pw.println("        boolean _equals;");
639         if (names.size() == 0) {
640             pw.println("        _equals = " + truth + ";");
641         } else if (isUnion()) {
642             pw.println("        _equals = " + truth + " && " +
643                     " this.toString().equals(obj.toString());");
644         } else {
645             pw.println("        _equals = " + truth + " && ");
646             for (int i = 0; i < names.size(); i += 2) {
647                 String variableType = (String) names.get(i);
648                 String variable = (String) names.get(i + 1);
649                 String get = "get";
650                 if (variableType.equals("boolean"))
651                     get = "is";
652                 if (variableType.equals("int") ||
653                         variableType.equals("long") ||
654                         variableType.equals("short") ||
655                         variableType.equals("float") ||
656                         variableType.equals("double") ||
657                         variableType.equals("boolean") ||
658                         variableType.equals("byte")) {
659                     pw.print("            this." + variable + " == other." + get +
660                             Utils.capitalizeFirstChar(variable) + "()");
661                 } else if (variableType.indexOf("[") >= 0) {
662                     // Use java.util.Arrays.equals to compare arrays.
663                     pw.println("            ((this." + variable +
664                             "==null && other." + get +
665                             Utils.capitalizeFirstChar(variable) + "()==null) || ");
666                     pw.println("             (this." + variable + "!=null &&");
667                     pw.print("              java.util.Arrays.equals(this." + variable +
668                             ", other." + get +
669                             Utils.capitalizeFirstChar(variable) + "())))");
670                 } else {
671                     pw.println("            ((this." + variable +
672                             "==null && other." + get +
673                             Utils.capitalizeFirstChar(variable) + "()==null) || ");
674                     pw.println("             (this." + variable + "!=null &&");
675                     pw.print("              this." + variable +
676                             ".equals(other." + get +
677                             Utils.capitalizeFirstChar(variable) + "())))");
678                 }
679                 if (i == (names.size() - 2))
680                     pw.println(";");
681                 else
682                     pw.println(" &&");
683             }
684         }
685         pw.println("        __equalsCalc = null;");
686         pw.println("        return _equals;");
687         pw.println("    }");
688         pw.println("");
689     }
690 
691     /***
692      * Writes a general purpose hashCode method.
693      */
694     protected void writeHashCodeMethod() {
695         // The __hashCodeCalc field and synchronized method are necessary
696         // in case the object has direct or indirect references to itself.
697         pw.println("    private boolean __hashCodeCalc = false;");
698         pw.println("    public synchronized int hashCode() {");
699         pw.println("        if (__hashCodeCalc) {");
700         pw.println("            return 0;");
701         pw.println("        }");
702         pw.println("        __hashCodeCalc = true;");
703 
704         // Get the hashCode of the super class
705         String start = "1";
706         if (extendType != null && !type.isSimpleType()) {
707             start = "super.hashCode()";
708         }
709         pw.println("        int _hashCode = " + start + ";");
710         if (isUnion()) {
711             pw.println("        if (this.value != null) {");
712             pw.println("            _hashCode += this.value.hashCode();");
713             pw.println("        }");
714         }
715         for (int i = 0; !isUnion() && (i < names.size()); i += 2) {
716             String variableType = (String) names.get(i);
717             String variable = (String) names.get(i + 1);
718             String get = "get";
719             if (variableType.equals("boolean"))
720                 get = "is";
721             if (variableType.equals("int") ||
722                     variableType.equals("short") ||
723                     variableType.equals("byte")) {
724                 pw.println("        _hashCode += " + get +
725                         Utils.capitalizeFirstChar(variable) + "();");
726             } else if (variableType.equals("boolean")) {
727                 pw.println("        _hashCode += (" + get +
728                         Utils.capitalizeFirstChar(variable) + "() ? Boolean.TRUE : Boolean.FALSE).hashCode();");
729             } else if (variableType.equals("long")) {
730                 pw.println("        _hashCode += new Long(" + get +
731                         Utils.capitalizeFirstChar(variable) + "()).hashCode();");
732             } else if (variableType.equals("float")) {
733                 pw.println("        _hashCode += new Float(" + get +
734                         Utils.capitalizeFirstChar(variable) + "()).hashCode();");
735             } else if (variableType.equals("double")) {
736                 pw.println("        _hashCode += new Double(" + get +
737                         Utils.capitalizeFirstChar(variable) + "()).hashCode();");
738             } else if (variableType.indexOf("[") >= 0) {
739                 // The hashCode calculation for arrays is complicated.
740                 // Wish there was a hashCode method in java.utils.Arrays !
741                 // Get the hashCode for each element of the array which is not an array.
742                 pw.println("        if (" + get +
743                         Utils.capitalizeFirstChar(variable) + "() != null) {");
744                 pw.println("            for (int i=0;");
745                 pw.println("                 i<java.lang.reflect.Array.getLength(" + get +
746                         Utils.capitalizeFirstChar(variable) + "());");
747                 pw.println("                 i++) {");
748                 pw.println("                java.lang.Object obj = java.lang.reflect.Array.get(" +
749                         get +
750                         Utils.capitalizeFirstChar(variable) + "(), i);");
751                 pw.println("                if (obj != null &&");
752                 pw.println("                    !obj.getClass().isArray()) {");
753                 pw.println("                    _hashCode += obj.hashCode();");
754                 pw.println("                }");
755                 pw.println("            }");
756                 pw.println("        }");
757             } else {
758                 pw.println("        if (" + get +
759                         Utils.capitalizeFirstChar(variable) + "() != null) {");
760                 pw.println("            _hashCode += " + get +
761                         Utils.capitalizeFirstChar(variable) + "().hashCode();");
762                 pw.println("        }");
763             }
764         }
765         // Reset the __hashCodeCalc variable and return
766         pw.println("        __hashCodeCalc = false;");
767         pw.println("        return _hashCode;");
768         pw.println("    }");
769         pw.println("");
770     }
771 } // class JavaBeanWriter