Skip to content

Commit

Permalink
FORGE-451:Warn a user if generating relationship CRUD screens and Has…
Browse files Browse the repository at this point in the history
…hCode/Equals are missing
  • Loading branch information
Matej Briskar committed Jun 6, 2014
1 parent 7710226 commit 9d0c327
Showing 1 changed file with 117 additions and 66 deletions.
183 changes: 117 additions & 66 deletions api/src/main/java/org/jboss/forge/roaster/model/util/Refactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,24 @@ public static void createHashCodeAndEquals(final JavaClassSource clazz)
* @param fields fields to be used in the equals/hashCode methods
*/
public static void createHashCodeAndEquals(final JavaClassSource clazz, final FieldSource<?>... fields)
{
createEquals(clazz,fields);
createHashCode(clazz,fields);
}

/**
* Create an <i>equals</i> implementation for the given class and fields. Callers must verify that
* the types of the fields override the default identity based equals implementation. No warnings are
* issued in an event where the field type uses the implementation of java.lang.Object.
*
* This method ignores static fields for generating the equals method, since they are ideally not meant
* to be used in these cases. Although transient fields could also be ignored, they are not since there is no
* mechanism to convey warnings (not errors) in this case.
*
* @param clazz class to be changed
* @param fields fields to be used in the equals/hashCode methods
*/
public static void createEquals(final JavaClassSource clazz, final FieldSource<?>... fields)
{
if (clazz == null)
{
Expand All @@ -103,16 +121,11 @@ public static void createHashCodeAndEquals(final JavaClassSource clazz, final Fi
}

String superEqualsCheck = "";
String defaultHashcode = "int result = 1;";
if (!clazz.getSuperType().equals("java.lang.Object"))
{
superEqualsCheck = "if (!super.equals(obj)) { return false;} ";
defaultHashcode = "int result = super.hashCode();";
}

boolean isTempFieldCreated = false;
StringBuilder fieldEqualityChecks = new StringBuilder();
StringBuilder hashCodeComputation = new StringBuilder();
for (FieldSource<?> field : fields)
{
if (field == null)
Expand All @@ -127,47 +140,126 @@ public static void createHashCodeAndEquals(final JavaClassSource clazz, final Fi
String fieldName = field.getName();
if (field.getType().isArray())
{
// if(!Arrays.equals(array, other.array)) {
// return false;
// }
fieldEqualityChecks.append("if (!Arrays.equals(").append(fieldName).append(", other.").append(fieldName)
.append(")) {");
fieldEqualityChecks.append(" return false; }");

// result = prime * result + Arrays.hashCode(array);
hashCodeComputation.append("result = prime * result + Arrays.hashCode(").append(fieldName).append(");");
}
else if (field.getType().isPrimitive())
{
if (field.getType().isType("float"))
{
// if(Float.floatToIntBits(floatValue) != Float.floatToIntBits(other.floatValue)) {
// return false;
// }
fieldEqualityChecks.append("if (Float.floatToIntBits(").append(fieldName)
.append(") != Float.floatToIntBits(other.").append(fieldName)
.append(")) { ");
fieldEqualityChecks.append(" return false;");
fieldEqualityChecks.append("} ");

// result = prime * result + Float.floatToIntBits(floatValue);
hashCodeComputation.append("result = prime * result + ").append("Float.floatToIntBits(")
.append(fieldName).append(");");
}
else if (field.getType().isType("double"))
{
// if(Double.doubleToLongBits(doubleValue) != Double.doubleToLongBits(other.doubleValue)) {
// return false;
// }
fieldEqualityChecks.append("if (Double.doubleToLongBits(").append(fieldName)
.append(") != Double.doubleToLongBits(other.").append(fieldName)
.append(")) { ");
fieldEqualityChecks.append(" return false;");
fieldEqualityChecks.append("} ");
}
else
{
fieldEqualityChecks.append("if (").append(fieldName).append(" != other.").append(fieldName)
.append(") { ");
fieldEqualityChecks.append(" return false;");
fieldEqualityChecks.append("} ");
}
}
else
{
fieldEqualityChecks.append("if (").append(fieldName).append(" != null) { ");
fieldEqualityChecks.append(" if(!").append(fieldName).append(".equals(");
fieldEqualityChecks.append("other.").append(fieldName);
fieldEqualityChecks.append(")) { return false;} } ");
}
}

if (fieldEqualityChecks.length() < 1 )
{
throw new IllegalArgumentException(
"A failure was detected when generating the equals and hashCode methods. Verify the type and modifiers of the provided fields.");
}

StringBuilder typeCheckAndAssignment = new StringBuilder();
String klassName = clazz.getName();

typeCheckAndAssignment.append("if (!(obj instanceof ").append(klassName).append(")) {");
typeCheckAndAssignment.append(" return false;}");
typeCheckAndAssignment.append(klassName).append(" other = (").append(klassName).append(") obj;");

clazz.addMethod(
"public boolean equals(Object obj) { " +
"if (this == obj) { return true; } " +
superEqualsCheck.toString() +
typeCheckAndAssignment.toString() +
fieldEqualityChecks.toString() +
"return true; " +
"}")
.addAnnotation(Override.class);
}

/**
* Create a <i>hashCode</i> implementation for the given class and fields. Callers must verify that
* the types of the fields override the default identity based hashcode implementation. No warnings are
* issued in an event where the field type uses the implementation of java.lang.Object.
*
* This method ignores static fields for generating the equals method, since they are ideally not meant
* to be used in these cases. Although transient fields could also be ignored, they are not since there is no
* mechanism to convey warnings (not errors) in this case.
*
* @param clazz class to be changed
* @param fields fields to be used in the equals/hashCode methods
*/
public static void createHashCode(final JavaClassSource clazz, final FieldSource<?>... fields)
{
if (clazz == null)
{
throw new IllegalArgumentException("The provided class cannot be null.");
}
if (fields == null || fields.length < 1)
{
throw new IllegalArgumentException("The provided fields cannot be null or empty.");
}

String defaultHashcode = "int result = 1;";
if (!clazz.getSuperType().equals("java.lang.Object"))
{
defaultHashcode = "int result = super.hashCode();";
}

// long temp;
// temp = Double.doubleToLongBits(doubleValue);
// result = prime * result + (int) (temp ^ (temp >>> 32));
boolean isTempFieldCreated = false;
StringBuilder hashCodeComputation = new StringBuilder();
for (FieldSource<?> field : fields)
{
if (field == null)
{
throw new IllegalArgumentException("A supplied field was null. The equals and hashCode computation will be aborted.");
}
if (field.isStatic())
{
throw new IllegalArgumentException("A static field was detected. The equals and hashCode computation will be aborted.");
}

String fieldName = field.getName();
if (field.getType().isArray())
{
hashCodeComputation.append("result = prime * result + Arrays.hashCode(").append(fieldName).append(");");
}
else if (field.getType().isPrimitive())
{
if (field.getType().isType("float"))
{
hashCodeComputation.append("result = prime * result + ").append("Float.floatToIntBits(")
.append(fieldName).append(");");
}
else if (field.getType().isType("double"))
{
if (!isTempFieldCreated)
{
hashCodeComputation.append("long temp;");
Expand All @@ -178,14 +270,6 @@ else if (field.getType().isType("double"))
}
else
{
// if(value != other.value) {
// return false;
// }
fieldEqualityChecks.append("if (").append(fieldName).append(" != other.").append(fieldName)
.append(") { ");
fieldEqualityChecks.append(" return false;");
fieldEqualityChecks.append("} ");

if (field.getType().isType("long"))
{
// result = prime * result + (int) (longValue ^ (longValue >>> 32));
Expand All @@ -208,49 +292,16 @@ else if (field.getType().isType("boolean"))
}
else
{
// if(value != null) {
// if(!value.equals(other.value)) {
// return false;
// }
// }
fieldEqualityChecks.append("if (").append(fieldName).append(" != null) { ");
fieldEqualityChecks.append(" if(!").append(fieldName).append(".equals(");
fieldEqualityChecks.append("other.").append(fieldName);
fieldEqualityChecks.append(")) { return false;} } ");

// result = prime * result + (( obj == null) ? 0 : obj.hashCode());
hashCodeComputation.append("result = prime * result + ((").append(fieldName).append(" == null) ? 0 : ")
.append(fieldName).append(".hashCode());");
}
}

if (fieldEqualityChecks.length() < 1 || hashCodeComputation.length() < 1)
if (hashCodeComputation.length() < 1)
{
throw new IllegalArgumentException(
"A failure was detected when generating the equals and hashCode methods. Verify the type and modifiers of the provided fields.");
}

StringBuilder typeCheckAndAssignment = new StringBuilder();
String klassName = clazz.getName();

// if (!(obj instanceof Type)) {
// return false;
// }
// Type other = (Type) obj;
typeCheckAndAssignment.append("if (!(obj instanceof ").append(klassName).append(")) {");
typeCheckAndAssignment.append(" return false;}");
typeCheckAndAssignment.append(klassName).append(" other = (").append(klassName).append(") obj;");

clazz.addMethod(
"public boolean equals(Object obj) { " +
"if (this == obj) { return true; } " +
superEqualsCheck.toString() +
typeCheckAndAssignment.toString() +
fieldEqualityChecks.toString() +
"return true; " +
"}")
.addAnnotation(Override.class);

clazz.addMethod(
"public int hashCode() { " +
"final int prime = 31;" +
Expand All @@ -259,7 +310,7 @@ else if (field.getType().isType("boolean"))
"return result; }")
.addAnnotation(Override.class);
}

/**
* Create a <i>toString</i> implementation using all the fields in this class
*
Expand Down

0 comments on commit 9d0c327

Please sign in to comment.