org.somda.sdc.biceps.model.plugins.CustomEqualsPlugin Maven / Gradle / Ivy
The newest version!
package org.somda.sdc.biceps.model.plugins;
import com.sun.codemodel.JBlock;
import com.sun.codemodel.JConditional;
import com.sun.codemodel.JExpr;
import com.sun.codemodel.JExpression;
import com.sun.codemodel.JForLoop;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
import com.sun.codemodel.JVar;
import com.sun.tools.xjc.Options;
import com.sun.tools.xjc.Plugin;
import com.sun.tools.xjc.outline.ClassOutline;
import com.sun.tools.xjc.outline.FieldOutline;
import com.sun.tools.xjc.outline.Outline;
import org.jvnet.jaxb.util.PropertyFieldAccessorFactory;
import org.jvnet.jaxb.xjc.outline.FieldAccessorEx;
import org.w3c.dom.Element;
import org.xml.sax.ErrorHandler;
import static com.sun.codemodel.JMod.PUBLIC;
/**
* A XJC Plugin to generate a custom equals method for ExtensionType
*/
public class CustomEqualsPlugin extends Plugin {
static final String CLASS_NAME = "ExtensionType";
static final String CUSTOM_IS_EQUAL_NODE_METHOD = "customIsEqualNode";
static final String EQUALS_METHOD = "equals";
static final String GET_CLASS_METHOD = "getClass";
static final String GET_METHOD = "get";
static final String IS_EMPTY_METHOD = "isEmpty";
static final String SIZE_METHOD = "size";
@Override
public String getOptionName() {
return "XcustomExtensionTypeEquals";
}
@Override
public String getUsage() {
return " -XcustomExtensionTypeEquals to generate a custom equals method that also considers unknown extensions.";
}
@Override
public boolean run(Outline outline, Options options, ErrorHandler errorHandler) {
for (ClassOutline o : outline.getClasses()) {
if (o.getImplClass().name().equals(CLASS_NAME)) {
// declare an equals method with an Object.class parameter named "object"
JMethod method = o.implClass.method(PUBLIC, boolean.class, EQUALS_METHOD);
method.annotate(Override.class);
JVar methodParameter = method.param(Object.class, "object");
JBlock methodBody = method.body();
JExpression _this = JExpr._this();
// return false if (object == null)||(this.getClass()!= object.getClass())
JExpression methodParameterNullOrDifferentClass = methodParameter.eq(JExpr._null()).cor(_this.invoke(GET_CLASS_METHOD).ne(methodParameter.invoke(GET_CLASS_METHOD)));
methodBody._if(methodParameterNullOrDifferentClass)._then()._return(JExpr.FALSE);
// return true if this == object
JExpression methodParameterIsThis = _this.eq(methodParameter);
methodBody._if(methodParameterIsThis)._then()._return(JExpr.TRUE);
FieldOutline[] fields = o.getDeclaredFields();
if (fields.length > 0) {
// cast parameter "object" to ExtensionType.java and assign it to a new variable "that"
JVar _that = methodBody.decl(JMod.FINAL, o.getImplClass(), "that", JExpr.cast(o.getImplClass(), methodParameter));
for (FieldOutline fieldOutline : fields) {
JBlock block = methodBody.block();
// get the name of the current field i.e. "any"
String fieldName = fieldOutline.getPropertyInfo().getName(true);
// field accessors for i.e. "any" of this and "that"
FieldAccessorEx leftFieldAccessor = PropertyFieldAccessorFactory.INSTANCE.createFieldAccessor(fieldOutline, _this);
FieldAccessorEx rightFieldAccessor = PropertyFieldAccessorFactory.INSTANCE.createFieldAccessor(fieldOutline, _that);
// declare two variables "left..." and "right..." and assign them the value of the field accessors
JVar leftValue = block.decl(leftFieldAccessor.getType(), "left" + fieldName);
leftFieldAccessor.toRawValue(block, leftValue);
JVar rightValue = block.decl(rightFieldAccessor.getType(), "right" + fieldName);
rightFieldAccessor.toRawValue(block, rightValue);
// if (left!= null)&&(!left.isEmpty())
JExpression leftNotNullNotEmptyExpression = leftValue.ne(JExpr._null()).cand(leftValue.invoke(IS_EMPTY_METHOD).not());
// if (right!= null)&&(!right.isEmpty())
JExpression rightNotNullNotEmptyExpression = rightValue.ne(JExpr._null()).cand(rightValue.invoke(IS_EMPTY_METHOD).not());
// if left.size()!= right.size()
JExpression notSameSizeExpression = leftValue.invoke(SIZE_METHOD).ne(rightValue.invoke(SIZE_METHOD));
// reference for the if statement of (left!= null)&&(!left.isEmpty()) to nest more if statements or declare an else-block
JConditional leftNotNullBlock = block._if(leftNotNullNotEmptyExpression);
// reference for the nested if-statement (right!= null)&&(!right.isEmpty()) to nest more if statements or declare an else-block
JConditional leftNotNullRightNotNullExpression = leftNotNullBlock._then()._if(rightNotNullNotEmptyExpression);
// return false if at least one of the lists contain an org.w3c.dom.Element but the lists are not of the same size
leftNotNullRightNotNullExpression._then()._if(notSameSizeExpression)._then()._return(JExpr.FALSE);
// declare a forLoop inside the if-block of (left.stream().anyMatch((Element.class::isInstance))||right.stream().anyMatch((Element.class::isInstance)))
JForLoop forLoop = leftNotNullRightNotNullExpression._then().block()._for();
JVar iVar = forLoop.init(o.parent().getCodeModel().INT, "i", JExpr.lit(0));
forLoop.test(iVar.lt(leftValue.invoke(SIZE_METHOD)));
forLoop.update(iVar.assignPlus(JExpr.lit(1)));
// if (left.get(i) instanceof Element)&&(right.get(i) instanceof Element)
JExpression bothElementsAreElementExpression = leftValue.invoke(GET_METHOD).arg(iVar)._instanceof(o.parent().getCodeModel().ref(Element.class)).cand(rightValue.invoke(GET_METHOD).arg(iVar)._instanceof(o.parent().getCodeModel().ref(Element.class)));
// reference for the if-statement (left.get(i) instanceof Element)&&(right.get(i) instanceof Element) in the for-loop
JConditional forLoopBothElement = forLoop.body()._if(bothElementsAreElementExpression);
// declare two variables "leftElement" and "rightElement" inside the if-block in the for-loop assign them the current viewed element from left and right casted to org.w3c.dom.Element and normalize them
JVar leftElement = forLoopBothElement._then().decl(JMod.FINAL, o.parent().getCodeModel().ref(Element.class), "leftElement", JExpr.cast(o.parent().getCodeModel().ref(Element.class), (leftValue.invoke(GET_METHOD).arg(iVar))));
JVar rightElement = forLoopBothElement._then().decl(JMod.FINAL, o.parent().getCodeModel().ref(Element.class), "rightElement", JExpr.cast(o.parent().getCodeModel().ref(Element.class), (rightValue.invoke(GET_METHOD).arg(iVar))));
// return false when !leftElement.isEqualNode(rightElement)
forLoopBothElement._then()._if((o.parent().getCodeModel().ref(PluginUtil.class).staticInvoke(CUSTOM_IS_EQUAL_NODE_METHOD).arg(leftElement).arg(rightElement).not()))._then()._return(JExpr.FALSE);
// if not both elements are instance of org.w3c.dom.Element but if !leftAny.get(i).equals(rightAny.get(i)) return false
forLoopBothElement._else()._if(leftValue.invoke(GET_METHOD).arg(iVar).invoke(EQUALS_METHOD).arg(rightValue.invoke(GET_METHOD).arg(iVar)).not())._then()._return(JExpr.FALSE);
// return false when (leftAny!= null)&&(!leftAny.isEmpty()) but not (rightAny!= null)&&(!rightAny.isEmpty())
leftNotNullRightNotNullExpression._else()._return(JExpr.FALSE);
// return false when not (leftAny!= null)&&(!leftAny.isEmpty()) but (rightAny!= null)&&(!rightAny.isEmpty())
leftNotNullBlock._else()._if(rightNotNullNotEmptyExpression)._then()._return(JExpr.FALSE);
}
}
methodBody._return(JExpr.TRUE);
}
}
return true;
}
}