Ibator includes EqualsHashCodePlugin by default.
It adds equals() and hashCode() methods to the domain classes.
As I want to add these methods to example classes, I wrote another plugin.
import java.util.Iterator;
import java.util.List;
import org.apache.ibatis.ibator.api.IbatorPluginAdapter;
import org.apache.ibatis.ibator.api.IntrospectedTable;
import org.apache.ibatis.ibator.api.dom.OutputUtilities;
import org.apache.ibatis.ibator.api.dom.java.Field;
import org.apache.ibatis.ibator.api.dom.java.FullyQualifiedJavaType;
import org.apache.ibatis.ibator.api.dom.java.InnerClass;
import org.apache.ibatis.ibator.api.dom.java.JavaVisibility;
import org.apache.ibatis.ibator.api.dom.java.Method;
import org.apache.ibatis.ibator.api.dom.java.Parameter;
import org.apache.ibatis.ibator.api.dom.java.TopLevelClass;
public class EqualsHashCodePlugin extends IbatorPluginAdapter
{
public boolean validate(List<String> warnings)
{
return true;
}
@Override
public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass,
IntrospectedTable introspectedTable)
{
generateEquals(introspectedTable, topLevelClass);
generateHashCode(introspectedTable, topLevelClass);
return true;
}
@Override
public boolean modelPrimaryKeyClassGenerated(TopLevelClass topLevelClass,
IntrospectedTable introspectedTable)
{
generateEquals(introspectedTable, topLevelClass);
generateHashCode(introspectedTable, topLevelClass);
return true;
}
@Override
public boolean modelRecordWithBLOBsClassGenerated(TopLevelClass topLevelClass,
IntrospectedTable introspectedTable)
{
generateEquals(introspectedTable, topLevelClass);
generateHashCode(introspectedTable, topLevelClass);
return true;
}
@Override
public boolean modelExampleClassGenerated(TopLevelClass topLevelClass,
IntrospectedTable introspectedTable)
{
generateEquals(introspectedTable, topLevelClass);
generateHashCode(introspectedTable, topLevelClass);
InnerClass innerClass = topLevelClass.getInnerClasses().get(0);
generateEquals(introspectedTable, innerClass);
generateHashCode(introspectedTable, innerClass);
return true;
}
private void generateHashCode(IntrospectedTable introspectedTable, InnerClass innerClass)
{
Iterator<Field> iter;
Method method = new Method();
method.setVisibility(JavaVisibility.PUBLIC);
method.setReturnType(FullyQualifiedJavaType.getIntInstance());
method.setName("hashCode");
if (introspectedTable.isJava5Targeted())
{
method.addAnnotation("@Override");
}
if (innerClass instanceof TopLevelClass)
{
ibatorContext.getCommentGenerator().addGeneralMethodComment(method,
introspectedTable);
}
method.addBodyLine("final int prime = 17;");
if (hasSuperClass(innerClass))
method.addBodyLine("int result = super.hashCode();");
else
method.addBodyLine("int result = 1;");
StringBuilder sb = new StringBuilder();
sb.setLength(0);
boolean bitsDeclared = false;
iter = innerClass.getFields().iterator();
while (iter.hasNext())
{
Field field = iter.next();
sb.setLength(0);
String property = field.getName();
FullyQualifiedJavaType type = field.getType();
if (type.isPrimitive())
{
String typeStr = type.getFullyQualifiedName();
if ("int".equals(typeStr))
{
sb.append("result = prime * result + ");
sb.append(property);
sb.append(";");
}
else if ("byte".equals(typeStr) || "char".equals(typeStr)
|| "short".equals(typeStr))
{
sb.append("result = prime * result + (int)");
sb.append(property);
sb.append(";");
}
else if ("long".equals(typeStr))
{
sb.append("result = prime * result + (int)(");
sb.append(property);
sb.append(" ^ (");
sb.append(property);
sb.append(" >>> 32));");
}
else if ("float".equals(typeStr))
{
sb.append("result = prime * result + Float.floatToIntBits(");
sb.append(property);
sb.append(");");
}
else if ("double".equals(typeStr))
{
if (!bitsDeclared)
{
sb.append("long ");
bitsDeclared = true;
}
sb.append("bits = Double.doubleToLongBits(");
sb.append(property);
sb.append(");");
sb.append("result = prime * result + (int)(bits ^ (bits >>> 32));");
}
else if ("boolean".equals(typeStr))
{
sb.append("result = prime * result + (");
sb.append(property);
sb.append(" ? 1 : 0);");
}
}
else
{
sb.append("result = prime * result + (null == ");
sb.append(property);
sb.append(" ? 0 : ");
sb.append(property);
sb.append(".hashCode());");
}
method.addBodyLine(sb.toString());
}
method.addBodyLine("return result;");
innerClass.addMethod(method);
}
/**
* @param introspectedTable
* @param innerClass
*/
private void generateEquals(IntrospectedTable introspectedTable, InnerClass innerClass)
{
Method method;
StringBuilder sb;
boolean first;
Iterator<Field> iter;
method = new Method();
method.setVisibility(JavaVisibility.PUBLIC);
method.setReturnType(FullyQualifiedJavaType.getBooleanPrimitiveInstance());
method.setName("equals");
method.addParameter(new Parameter(FullyQualifiedJavaType.getObjectInstance(), "that"));
if (introspectedTable.isJava5Targeted())
{
method.addAnnotation("@Override");
}
if (innerClass instanceof TopLevelClass)
{
ibatorContext.getCommentGenerator().addGeneralMethodComment(method,
introspectedTable);
}
method.addBodyLine("if (this == that)");
method.addBodyLine("return true;");
if (hasSuperClass(innerClass))
{
method.addBodyLine("if (!super.equals(that))");
method.addBodyLine("return false;");
}
sb = new StringBuilder();
sb.append("if((that == null) || (that.getClass() != this.getClass()))");
method.addBodyLine(sb.toString());
method.addBodyLine("return false;");
sb.setLength(0);
sb.append(innerClass.getType().getShortName());
sb.append(" other = (");
sb.append(innerClass.getType().getShortName());
sb.append(") that;");
method.addBodyLine(sb.toString());
sb.setLength(0);
first = true;
iter = innerClass.getFields().iterator();
while (iter.hasNext())
{
Field field = iter.next();
sb.setLength(0);
if (first)
{
sb.append("return ");
first = false;
}
else
{
OutputUtilities.javaIndent(sb, 1);
sb.append("&& ");
}
String property = field.getName();
FullyQualifiedJavaType type = field.getType();
if (type.isPrimitive())
{
sb.append(property);
sb.append(" == other.");
sb.append(property);
}
else
{
sb.append("(");
sb.append(property);
sb.append(" == other.");
sb.append(property);
sb.append(" || (");
sb.append(property);
sb.append(" != null && ");
sb.append(property);
sb.append(".equals(other.");
sb.append(property);
sb.append(")))");
}
if (!iter.hasNext())
{
sb.append(';');
}
method.addBodyLine(sb.toString());
}
innerClass.addMethod(method);
}
private boolean hasSuperClass(InnerClass innerClass)
{
return null != innerClass.getSuperClass();
}
}
It is useful when I use those classes with Mockito.
Note that this plugin generates the methods for domain classes as well, so don't use it with the default EqualsHashCodePlugin.
No comments:
Post a Comment