Hi Keith, Arnaud et al.,
 
Part of my recent work has been to replace DTOs in an application with Castor-generated classes.  To do this, I needed to implement the following "standard" methods in each generated class, in addition to equals():
  • a full-argument constructor
  • a copy-constructor
  • hashCode()
  • toString() for debug
  • clone()
(There is an overlap between usage of the copy-constructor and clone()).
 
Attached are methods for generating this code which I have inserted into org.exolab.castor.builder.SourceFactory.  I hooked into these methods from SourceFactory.createSourceCode(XMLBindingComponent, SGStateInfo) as follows:
//create equals() method?
if (component.hasEquals())
    createEqualsMethod(jClass, component.hasHashcode());
//create hashCode() method?
if (component.hasHashcode())
    createHashCodeMethod(jClass, component.hasEquals());
if (component.hasToString())
    createToStringMethod(jClass);
if (component.hasClone()) {
    jClass.addInterface("Cloneable");
    createCloneMethod(jClass);
}
if (component.hasFullConstructor())
    createFullConstructor(jClass);
if (component.hasCopyConstructor())
    createCopyConstructor(jClass);
 
 
I hope you can make use of these.
 
 
 
Regards
Dean
 
 
 
 
intelli WHERE www.intelliwhere.com

Dr. Dean Chalker 
Distinguished Design Engineer (R&D)
[EMAIL PROTECTED]

IntelliWhere Division,  Intergraph Corporation
Australia

Phone: 61-7-3510 8918 
Fax: 61-7-3510 8901 
 
 
 
    /**
     * Create a 'hashCode' method on the given
     * JClass
     * @param jclass the Jclass in which we create the hashCode method
     * @param hasEquals <code>true</code> if the equals() method is also being
     *          generated
     */
     public static void createHashCodeMethod(JClass jclass, boolean hasEquals) {
         if (jclass == null)
            throw new IllegalArgumentException("JClass must not be null");

        JField[] fields = jclass.getFields();
        JMethod jMethod = new JMethod(JType.Int, "hashCode");
        jMethod.setComment("Override the java.lang.Object.hashCode method");
        if (!hasEquals) {
                jMethod.setComment("Note: equals() has not been overriden");
        }
        jclass.addMethod(jMethod);
        JSourceCode jsc = jMethod.getSourceCode();
        
        // implemented from Effective Java by JOshua Bloch: item 8
        jsc.add("int result = 17;");
        for (int i = 0; i <fields.length; i++) {
            JField temp = fields[i];
            //Be careful to arrayList....

            String name = temp.getName();
            JType type = temp.getType();
            
            if (type.isPrimitive()) {
                if (!temp.isAuxiliary()) {
                        jsc.add("result = 37*result + (_has" + name + " ? 0 : 1);");
                        //check first if the field
                        //is not null. This can occur while comparing
                        //two objects that contains non-mandatory fields.
                        jsc.add("if (_has" + name + ")");
                            if (type == JType.Boolean) {
                                jsc.indent();
                                jsc.add("result = 37*result + (" + name + " ? 0 : 
1);");
                                jsc.unindent();
                            } else if (type == JType.Byte || type == JType.Char || 
type == JType.Short) {
                                jsc.indent();
                                jsc.add("result = 37*result + (int)" + name + ";");
                                jsc.unindent();
                            } else if (type == JType.Int) {
                                jsc.indent();
                                jsc.add("result = 37*result + " + name + ";");
                                jsc.unindent();
                            } else if (type == JType.Long) {
                                jsc.indent();
                                jsc.add("result = 37*result + (int)(" + name + " ^ (" 
+ name + " >>> 32));");
                                jsc.unindent();
                            } else if (type == JType.Float) {
                                jsc.indent();
                                jsc.add("result = 37*result + Float.floatToIntBits(" + 
name +");");
                                jsc.unindent();
                            } else if (type == JType.Double) {
                                jsc.append(" {");
                                jsc.indent();
                                jsc.add("long " + name + "L = 
Double.doubleToLongBits(" + name + ");");
                                jsc.add("result = 37*result + (int)(" + name + "L ^ (" 
+ name + "L >>> 32));");
                                jsc.unindent();
                                jsc.add("}");
                            }
                }
            } else {
                jsc.add("result = 37*result + ((" + name + " != null) ? " + name + 
".hashCode() : 0);");
                }
        }
                jsc.add("return result;");
                
     }//createHashcodeMethod

    /**
     * Create a 'toString' method on the given
     * JClass
     * @param jclass the Jclass in which we create the toString method
     */
     public static void createToStringMethod(JClass jclass) {
         if (jclass == null)
            throw new IllegalArgumentException("JClass must not be null");

        JField[] fields = jclass.getFields();
        JMethod jMethod = new JMethod(new JClass("java.lang.String"), "toString");
        jMethod.setComment("Override the java.lang.Object.toString method");
        jclass.addMethod(jMethod);
        JSourceCode jsc = jMethod.getSourceCode();
        
        jsc.add("return \"[\"");
        jsc.indent();
        
        for (int i = 0; i <fields.length; i++) {
            JField temp = fields[i];
            //Be careful to arrayList....

            String name = temp.getName();
            JType type = temp.getType();
            
                
            if (type.isPrimitive()) {
                if (!temp.isAuxiliary()) {
                                jsc.add("+ \"");
                                if (i != 0) {
                                        jsc.append(" ");
                                }
                                jsc.append(name + ":\"");
                                
                        //check first if the field
                        //is not null. This can occur while comparing
                        //two objects that contains non-mandatory fields.
                        jsc.append(" + (_has" + name + " ? ");
                            if (type == JType.Boolean) {
                                jsc.append("(" + name + " ? \"true\" : \"false\")");
                            } else if (type == JType.Byte) {
                                jsc.append("Integer.toString(" + name + ", 16)");
                            } else if (type == JType.Char) {
                                jsc.append("new Character(" + name + ").toString()");
                            } else if (type == JType.Short) {
                                jsc.append("Short.toString(" + name + ")");
                            } else if (type == JType.Int) {
                                jsc.append("Integer.toString(" + name + ")");
                            } else if (type == JType.Long) {
                                jsc.append("Long.toString(" + name + ")");
                                jsc.append("");
                            } else if (type == JType.Float) {
                                jsc.append("Float.toString(" + name + ")");
                            } else if (type == JType.Double) {
                                jsc.append("Double.toString(" + name + ")");
                            }
                        jsc.append(" : \"null\")");
                }
            } else {
                        jsc.add("+ \"");
                        if (i != 0) {
                                jsc.append(" ");
                        }
                        jsc.append(name + ":\" + " + name);
            }
        }
        
        jsc.add("+ \"]\";");
        jsc.unindent();
     }//createToStringMethod
     
    /**
     * Create a 'clone' method on the given
     * JClass
     * @param jclass the Jclass in which we create the clone method
     */
     public static void createCloneMethod(JClass jclass) {
         if (jclass == null)
            throw new IllegalArgumentException("JClass must not be null");

        JField[] fields = jclass.getFields();
        JMethod jMethod = new JMethod(new JClass("java.lang.Object"), "clone");
        jMethod.setComment("Override the java.lang.Object.clone method");
        jclass.addMethod(jMethod);
        JSourceCode jsc = jMethod.getSourceCode();
        
        jsc.add("try {");
        jsc.indent();
        
        jsc.add(jclass.getLocalName() + " result = (" + jclass.getLocalName() + 
")super.clone();");
        
        for (int i = 0; i <fields.length; i++) {
            JField temp = fields[i];
            //Be careful to arrayList....

            String name = temp.getName();
            JType type = temp.getType();
                
            if (!type.isPrimitive()) {
                // @todo need to figure out the immutable classes
                if (!type.getName().equals("java.lang.String")
                                && !type.getName().equals("java.math.BigDecimal")
                                && !type.getName().equals("byte")) {
                        jsc.add("if(" + name + " != null)");
                                jsc.indent();
                                jsc.add("result." + name + " = (" + type.getName() + 
")this." + name + ".clone();");
                                jsc.unindent();
                }
            }
        }
        
        jsc.add("return result;");
        jsc.unindent();
        jsc.add("} catch (CloneNotSupportedException e) {");
        jsc.indent();
        jsc.add("throw new RuntimeException(e.getMessage());");
        jsc.unindent();
        jsc.add("}");
        
     }//createCloneMethod
     
    /**
     * Create a full-argument constructor on the given
     * JClass
     * @param jclass the Jclass in which we create the constructor
     */
     public static void createFullConstructor(JClass jclass) {
         if (jclass == null)
            throw new IllegalArgumentException("JClass must not be null");

        JField[] fields = jclass.getFields();
        int paramCount = 0;
        for (int i = 0; i <fields.length; i++) {
            JField temp = fields[i];
            if (!temp.isAuxiliary()) {
                ++paramCount;
            }
        }
        
        JParameter[] params = new JParameter[paramCount];
        for (int i = 0, p = 0; i <fields.length; i++) {
            JField temp = fields[i];

            String name = temp.getName();
                // parameters are named without the leading underscore
            String paramName = name.substring(1);
            JType type = temp.getType();
                
            if (!temp.isAuxiliary()) {
                params[p++] = new JParameter(type, paramName);
            }
        }
        
        JConstructor jConstructor = jclass.createConstructor(params);
        JSourceCode jsc = jConstructor.getSourceCode();
        
        for (int i = 0, p = 0; i <fields.length; i++) {
            JField temp = fields[i];

            String name = temp.getName();
                // parameters are named without the leading underscore
            String paramName = name.substring(1);
            JType type = temp.getType();

            if (!temp.isAuxiliary()) {
                                jsc.add("this." + name + " = " + paramName + ";");
                        if (type.isPrimitive()) {
                                jsc.add("this._has" + name + " = true;");
                        }
                }
        }
        
     }//createFullConstructor
     
    /**
     * Create a copy constructor on the given
     * JClass
     * @param jclass the Jclass in which we create the constructor
     */
     public static void createCopyConstructor(JClass jclass) {
         if (jclass == null)
            throw new IllegalArgumentException("JClass must not be null");

        JField[] fields = jclass.getFields();
        String paramName = jclass.getLocalName().toLowerCase();
        JParameter[] params = new JParameter[]{
                        new JParameter(jclass, paramName),
                        new JParameter(JClass.Boolean, "deepCopy")
                };
        JConstructor jConstructor = jclass.createConstructor(params);
        JSourceCode jsc = jConstructor.getSourceCode();

                // determine whether we need to generate deep-copy code
                boolean needDeepCopy = false;
        for (int i = 0, p = 0; i < fields.length; i++) {
            JType type = fields[i].getType();
                // @todo need to figure out the immutable classes
                if (!type.isPrimitive()
                        && !type.getName().equals("java.lang.String")
                        && !type.getName().equals("java.math.BigDecimal")
                        && !type.getName().equals("byte")) {
                needDeepCopy = true;
                break;
                }
        }

                if (needDeepCopy) {             
                        jsc.add("if (deepCopy) {");
                        jsc.indent();
                        // this loop generate initialisation code for fields that are 
being deep-copied
                for (int i = 0, p = 0; i < fields.length; i++) {
                    JField temp = fields[i];
                    String name = temp.getName();
                    JType type = temp.getType();
                    
                   //Collection needs a specific handling
                   if ( (type.getName().equals("java.util.Vector")) ||
                                (type.getName().equals("java.util.ArrayList")) ) {
                        // if we are dealing with a Vector or an ArrayList
                        // we retrieve the type included in this Collection
                        // - but there should be an easier way
                        int listLocat = name.lastIndexOf("List");
                        String tempName = name;
                        if (listLocat != -1)
                           tempName = tempName.substring(0,listLocat);
                        if (tempName.charAt(0) == '_')
                           tempName = tempName.substring(1);
                        String methodName = JavaNaming.toJavaClassName(tempName);
                        methodName = "get"+methodName;
                        JMethod method = jclass.getMethod(methodName,0);
                        //@todo handle the Item introduced in with the group handling
                        if (method == null)
                            continue;
        
                        String componentName = method.getReturnType().getName();
                        
                        // for primitive (immutable) components, generate code like:
                                        //      this._xList = 
(java.util.ArrayList)arg._xList.clone();
                        // @todo handle primitives better
                        if (componentName.equals("boolean")
                                        || componentName.equals("byte")
                                        || componentName.equals("int")
                                        || componentName.equals("long")
                                        || componentName.equals("float")
                                        || componentName.equals("double")
                                        || componentName.equals("java.lang.String")
                                                        || 
componentName.equals("java.math.BigDecimal")) {
                                                jsc.add("this." + name + " = (" + type 
+ ")" + name + ".clone();");
                                        } else {
                                // generate code like:
                                                //      this._xList = new 
java.util.ArrayList(arg._xList.size());
                                                //      java.util.Iterator _xListIter 
= arg._xList.iterator();
                                                //      while (_sListIter.hasNext()) {
                                                //              this._xList.add(new 
X((X)_xListIter.next(), true));
                                                //      }
                                jsc.add("");
                                    jsc.add("this." + name + " = new " + type + "(" + 
paramName + "." + name + ".size());");
                                jsc.add("java.util.Iterator " + name + "Iter = " + 
paramName + "." + name + ".iterator();");
                                jsc.add("while (" + name + "Iter.hasNext()) {");
                                                jsc.indent();
                                                // @todo need to determine which are 
generated components, and which are not
                                jsc.add("this." + name + ".add(new " + componentName + 
"((" + componentName + ")" + name + "Iter.next(), true));");
                                                jsc.unindent();
                                                jsc.add("}");
                                jsc.add("");
                                        }
                        // @todo need to figure out the immutable classes
                        } else if (!type.isPrimitive()
                                && !type.getName().equals("java.lang.String")
                                && !type.getName().equals("java.math.BigDecimal")
                                && !type.getName().equals("byte")) {
                                
                        // generate code like:
                                        //      if (arg._x != null)
                                        //              this._x = new X(arg._x, true);
                        jsc.add("if (" + paramName + "." + name + " != null)");
                                        jsc.indent();
                        jsc.add("this." + name + " = new " + type + "(" + paramName + 
"." + name + ", true);");
                                        jsc.unindent();
                    }
                }
                        jsc.unindent();
                
                        jsc.add("} else {");
                        jsc.indent();
                        // this loop generate initialisation code for fields that 
could be deep-copied but aren't
                for (int i = 0, p = 0; i < fields.length; i++) {
                    JField temp = fields[i];
                    String name = temp.getName();
                    JType type = temp.getType();
                    
                        if (!type.isPrimitive()
                                && !type.getName().equals("java.lang.String")
                                && !type.getName().equals("java.math.BigDecimal")
                                && !type.getName().equals("byte")) {
                            // generate code like:
                                        //      this._x = arg._x;
                            jsc.add("this." + name + " = " + paramName + "." + name + 
";");
                        }
                }
                        jsc.unindent();
                        jsc.add("}");
                }
                
                // this loop generate initialisation code for fields that don't need 
to be deep-copied
        for (int i = 0, p = 0; i < fields.length; i++) {
            JField temp = fields[i];
            String name = temp.getName();
            JType type = temp.getType();
            
                if (type.isPrimitive()
                        || type.getName().equals("java.lang.String")
                        || type.getName().equals("java.math.BigDecimal")
                        || type.getName().equals("byte")) {
                    // generate code like:
                                //      this._x = arg._x;
                    jsc.add("this." + name + " = " + paramName + "." + name + ";");
                }
                }
        
     }//createCopyConstructor
     

Reply via email to