All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy