private void addEquals(JDefinedClass jclass, JsonNode node) {
    Map<String, JFieldVar> fields = removeFieldsExcludedFromEqualsAndHashCode(jclass.fields(), node);

    JMethod equals = jclass.method(JMod.PUBLIC, boolean.class, "equals");
    JVar otherObject = equals.param(Object.class, "other");

    JBlock body = equals.body();

    body._if(otherObject.eq(JExpr._this()))._then()._return(JExpr.TRUE);
    body._if(otherObject._instanceof(jclass).eq(JExpr.FALSE))._then()._return(JExpr.FALSE);

    JVar rhsVar = body.decl(jclass, "rhs").init(JExpr.cast(jclass, otherObject));

    JExpression result = JExpr.lit(true);

    // First, check super.equals(other)
    if (!jclass._extends().fullName().equals(Object.class.getName())) {
      result = result.cand(JExpr._super().invoke("equals").arg(rhsVar));
    }

    // Chain the results of checking all other fields
    for (JFieldVar fieldVar : fields.values()) {
      if ((fieldVar.mods().getValue() & JMod.STATIC) == JMod.STATIC) {
        continue;
      }

      JFieldRef thisFieldRef = JExpr.refthis(fieldVar.name());
      JFieldRef otherFieldRef = JExpr.ref(rhsVar, fieldVar.name());
      JExpression fieldEquals;

      if (fieldVar.type().isPrimitive()) {
        if ("double".equals(fieldVar.type().name())) {
          JClass doubleClass = jclass.owner().ref(Double.class);
          fieldEquals = doubleClass.staticInvoke("doubleToLongBits").arg(thisFieldRef).eq(
            doubleClass.staticInvoke("doubleToLongBits").arg(otherFieldRef));
        }
        else if ("float".equals(fieldVar.type().name())) {
          JClass floatClass = jclass.owner().ref(Float.class);
          fieldEquals = floatClass.staticInvoke("floatToIntBits").arg(thisFieldRef).eq(
            floatClass.staticInvoke("floatToIntBits").arg(otherFieldRef));
        }
        else {
          fieldEquals = thisFieldRef.eq(otherFieldRef);
        }
      }
      else if (fieldVar.type().isArray()) {
        if (!fieldVar.type().elementType().isPrimitive()) {
          throw new UnsupportedOperationException("Only primitive arrays are supported");
        }

        fieldEquals = jclass.owner().ref(Arrays.class).staticInvoke("equals").arg(thisFieldRef).arg(otherFieldRef);
      }
      else {
        fieldEquals = thisFieldRef.eq(otherFieldRef).cor(
          thisFieldRef.ne(JExpr._null())
            .cand(thisFieldRef.invoke("equals").arg(otherFieldRef)));
      }

      // Chain the equality of this field with the previous comparisons
      result = result.cand(fieldEquals);
    }

    body._return(result);

    equals.annotate(Override.class);
  }
private void addEquals(JDefinedClass jclass, JsonNode node)