Author: jgbutler Date: Tue Apr 20 17:10:50 2010 New Revision: 935997 URL: http://svn.apache.org/viewvc?rev=935997&view=rev Log: [ibator] improve generated equals and hashCode methods
Modified: ibatis/java/ibator/trunk/core/ibator-core/doc/ReleaseNotes.txt ibatis/java/ibator/trunk/core/ibator-core/doc/html/whatsNew.html ibatis/java/ibator/trunk/core/ibator-core/src/main/java/org/apache/ibatis/ibator/plugins/EqualsHashCodePlugin.java Modified: ibatis/java/ibator/trunk/core/ibator-core/doc/ReleaseNotes.txt URL: http://svn.apache.org/viewvc/ibatis/java/ibator/trunk/core/ibator-core/doc/ReleaseNotes.txt?rev=935997&r1=935996&r2=935997&view=diff ============================================================================== --- ibatis/java/ibator/trunk/core/ibator-core/doc/ReleaseNotes.txt (original) +++ ibatis/java/ibator/trunk/core/ibator-core/doc/ReleaseNotes.txt Tue Apr 20 17:10:50 2010 @@ -46,6 +46,7 @@ Enhancements: 19. Added new "or" method to example classes 20. Added new "useCompoundPropertyNames" property on <table> 21. Further improved extensibility of the example classes +22. EqulasHashCodePlugin now generates far superior methods ------------------------------------------------------------------------------- Modified: ibatis/java/ibator/trunk/core/ibator-core/doc/html/whatsNew.html URL: http://svn.apache.org/viewvc/ibatis/java/ibator/trunk/core/ibator-core/doc/html/whatsNew.html?rev=935997&r1=935996&r2=935997&view=diff ============================================================================== --- ibatis/java/ibator/trunk/core/ibator-core/doc/html/whatsNew.html (original) +++ ibatis/java/ibator/trunk/core/ibator-core/doc/html/whatsNew.html Tue Apr 20 17:10:50 2010 @@ -130,6 +130,7 @@ to iBATIS 3.x only requires two changes <li>Added new "or" method to example classes</li> <li>Added new "useCompoundPropertyNames" property on <table></li> <li>Enabled a far simpler method for extending the example classes</li> + <li>EqualsHashCodePlugin now generates far superior methods</li> </ul> Modified: ibatis/java/ibator/trunk/core/ibator-core/src/main/java/org/apache/ibatis/ibator/plugins/EqualsHashCodePlugin.java URL: http://svn.apache.org/viewvc/ibatis/java/ibator/trunk/core/ibator-core/src/main/java/org/apache/ibatis/ibator/plugins/EqualsHashCodePlugin.java?rev=935997&r1=935996&r2=935997&view=diff ============================================================================== --- ibatis/java/ibator/trunk/core/ibator-core/src/main/java/org/apache/ibatis/ibator/plugins/EqualsHashCodePlugin.java (original) +++ ibatis/java/ibator/trunk/core/ibator-core/src/main/java/org/apache/ibatis/ibator/plugins/EqualsHashCodePlugin.java Tue Apr 20 17:10:50 2010 @@ -37,10 +37,9 @@ import org.apache.ibatis.ibator.internal * cases, but will probably NOT be correct if you have specified a rootClass - * because our equals method only checks the fields it knows about. * <p> - * The <tt>hashCode</tt> method generated by this class is a very simplistic - * implementation. A better implementation would rely on the HashCodeUtil - * from www.javapractices.com - but we do not want to introduce another - * dependency in this simple plugin. + * Similarly, the <tt>hashCode</tt> method generated by this class only + * relies on fields it knows about. Anything you add, or fields in a super + * class will not be factored into the hash code. * * @author Jeff Butler * @@ -131,15 +130,15 @@ public class EqualsHashCodePlugin extend method.addBodyLine("return true;"); //$NON-NLS-1$ method.addBodyLine("}"); //$NON-NLS-1$ - StringBuilder sb = new StringBuilder(); - sb.append("if (!(that instanceof "); //$NON-NLS-1$ - sb.append(topLevelClass.getType().getShortName()); - sb.append(")) {"); //$NON-NLS-1$ - method.addBodyLine(sb.toString()); + method.addBodyLine("if (that == null) {"); //$NON-NLS-1$ method.addBodyLine("return false;"); //$NON-NLS-1$ method.addBodyLine("}"); //$NON-NLS-1$ - - sb.setLength(0); + + method.addBodyLine("if (getClass() != that.getClass()) {"); //$NON-NLS-1$ + method.addBodyLine("return false;"); //$NON-NLS-1$ + method.addBodyLine("}"); //$NON-NLS-1$ + + StringBuilder sb = new StringBuilder(); sb.append(topLevelClass.getType().getShortName()); sb.append(" other = ("); //$NON-NLS-1$ sb.append(topLevelClass.getType().getShortName()); @@ -196,10 +195,10 @@ public class EqualsHashCodePlugin extend } /** - * Generates a <tt>hashCode</tt> method that multiplies the hashCodes of - * all fields. + * Generates a <tt>hashCode</tt> method that includes all fields. * <p> - * Note that this is a very simplistic implementation of hashCode. + * Note that this implementation is based on the eclipse foundation + * hashCode generator. * * @param topLevelClass the class to which the method will be added * @param introspectedColumns column definitions of this class and @@ -221,69 +220,85 @@ public class EqualsHashCodePlugin extend ibatorContext.getCommentGenerator().addGeneralMethodComment(method, introspectedTable); - method.addBodyLine("int hash = 23;"); //$NON-NLS-1$ + method.addBodyLine("final int prime = 31;"); //$NON-NLS-1$ + method.addBodyLine("int result = 1;"); //$NON-NLS-1$ StringBuilder sb = new StringBuilder(); - boolean valueDeclared = false; - + boolean hasTemp = false; Iterator<IntrospectedColumn> iter = introspectedColumns.iterator(); while (iter.hasNext()) { IntrospectedColumn introspectedColumn = iter.next(); - FullyQualifiedJavaType fqjt = introspectedColumn .getFullyQualifiedJavaType(); String getterMethod = JavaBeansUtil.getGetterMethodName( introspectedColumn.getJavaProperty(), fqjt); + sb.setLength(0); if (fqjt.isPrimitive()) { - boolean cast = false; if ("boolean".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$ - // no adding the booleans to the hashCode computation - continue; - } else if ("long".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$ - cast = true; + sb.append("result = prime * result + ("); //$NON-NLS-1$ + sb.append(getterMethod); + sb.append("() ? 1231 : 1237);"); //$NON-NLS-1$ + method.addBodyLine(sb.toString()); + } else if ("byte".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$ + sb.append("result = prime * result + "); //$NON-NLS-1$ + sb.append(getterMethod); + sb.append("();"); //$NON-NLS-1$ + method.addBodyLine(sb.toString()); + } else if ("char".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$ + sb.append("result = prime * result + "); //$NON-NLS-1$ + sb.append(getterMethod); + sb.append("();"); //$NON-NLS-1$ + method.addBodyLine(sb.toString()); } else if ("double".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$ - cast = true; + if (!hasTemp) { + method.addBodyLine("long temp;"); //$NON-NLS-1$ + hasTemp = true; + } + sb.append("temp = Double.doubleToLongBits("); //$NON-NLS-1$ + sb.append(getterMethod); + sb.append("());"); //$NON-NLS-1$ + method.addBodyLine(sb.toString()); + method.addBodyLine("result = prime * result + (int) (temp ^ (temp >>> 32));"); //$NON-NLS-1$ } else if ("float".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$ - cast = true; - } - - sb.setLength(0); - if (!valueDeclared) { - sb.append("int "); //$NON-NLS-1$ - valueDeclared = true; - } - sb.append("value = "); //$NON-NLS-1$ - if (cast) { - sb.append("(int) "); //$NON-NLS-1$ + sb.append("result = prime * result + Float.floatToIntBits("); //$NON-NLS-1$ + sb.append(getterMethod); + sb.append("());"); //$NON-NLS-1$ + method.addBodyLine(sb.toString()); + } else if ("int".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$ + sb.append("result = prime * result + "); //$NON-NLS-1$ + sb.append(getterMethod); + sb.append("();"); //$NON-NLS-1$ + method.addBodyLine(sb.toString()); + } else if ("long".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$ + sb.append("result = prime * result + (int) ("); //$NON-NLS-1$ + sb.append(getterMethod); + sb.append("() ^ ("); //$NON-NLS-1$ + sb.append(getterMethod); + sb.append("() >>> 32));"); //$NON-NLS-1$ + method.addBodyLine(sb.toString()); + } else if ("short".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$ + sb.append("result = prime * result + "); //$NON-NLS-1$ + sb.append(getterMethod); + sb.append("();"); //$NON-NLS-1$ + method.addBodyLine(sb.toString()); + } else { + // should never happen + continue; } - sb.append(getterMethod); - sb.append("();"); //$NON-NLS-1$ - method.addBodyLine(sb.toString()); - - method.addBodyLine("if (value != 0) {"); //$NON-NLS-1$ - method.addBodyLine("hash *= value;"); //$NON-NLS-1$ - method.addBodyLine("}"); //$NON-NLS-1$ } else { - sb.setLength(0); - sb.append("if ("); //$NON-NLS-1$ + sb.append("result = prime * result + (("); //$NON-NLS-1$ sb.append(getterMethod); - sb.append("() != null) {"); //$NON-NLS-1$ - method.addBodyLine(sb.toString()); - - sb.setLength(0); - sb.append("hash *= "); //$NON-NLS-1$ + sb.append("() == null) ? 0 : "); //$NON-NLS-1$ sb.append(getterMethod); - sb.append("().hashCode();"); //$NON-NLS-1$ + sb.append("().hashCode());"); //$NON-NLS-1$ method.addBodyLine(sb.toString()); - - method.addBodyLine("}"); //$NON-NLS-1$ } } - method.addBodyLine("return hash;"); //$NON-NLS-1$ + method.addBodyLine("return result;"); //$NON-NLS-1$ topLevelClass.addMethod(method); }