package org.jvnet.jaxb2_commons.plugin.equals;
import java.util.Arrays;
import java.util.Collection;
import javax.xml.namespace.QName;
import org.jvnet.jaxb2_commons.lang.Equals;
import org.jvnet.jaxb2_commons.lang.EqualsStrategy;
import org.jvnet.jaxb2_commons.lang.JAXBEqualsStrategy;
import org.jvnet.jaxb2_commons.locator.ObjectLocator;
import org.jvnet.jaxb2_commons.locator.util.LocatorUtils;
import org.jvnet.jaxb2_commons.plugin.AbstractParameterizablePlugin;
import org.jvnet.jaxb2_commons.plugin.Customizations;
import org.jvnet.jaxb2_commons.plugin.CustomizedIgnoring;
import org.jvnet.jaxb2_commons.plugin.Ignoring;
import org.jvnet.jaxb2_commons.plugin.util.FieldOutlineUtils;
import org.jvnet.jaxb2_commons.plugin.util.StrategyClassUtils;
import org.jvnet.jaxb2_commons.util.ClassUtils;
import org.jvnet.jaxb2_commons.util.FieldAccessorFactory;
import org.jvnet.jaxb2_commons.util.PropertyFieldAccessorFactory;
import org.jvnet.jaxb2_commons.xjc.outline.FieldAccessorEx;
import org.xml.sax.ErrorHandler;
import com.sun.codemodel.JBlock;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JConditional;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JExpr;
import com.sun.codemodel.JExpression;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
import com.sun.codemodel.JOp;
import com.sun.codemodel.JVar;
import com.sun.tools.xjc.Options;
import com.sun.tools.xjc.outline.ClassOutline;
import com.sun.tools.xjc.outline.FieldOutline;
import com.sun.tools.xjc.outline.Outline;
public class EqualsPlugin extends AbstractParameterizablePlugin {
@Override
public String getOptionName() {
return "Xequals";
}
@Override
public String getUsage() {
return "TBD";
}
private FieldAccessorFactory fieldAccessorFactory = PropertyFieldAccessorFactory.INSTANCE;
public FieldAccessorFactory getFieldAccessorFactory() {
return fieldAccessorFactory;
}
public void setFieldAccessorFactory(
FieldAccessorFactory fieldAccessorFactory) {
this.fieldAccessorFactory = fieldAccessorFactory;
}
private String equalsStrategyClass = JAXBEqualsStrategy.class.getName();
public void setEqualsStrategyClass(String equalsStrategyClass) {
this.equalsStrategyClass = equalsStrategyClass;
}
public String getEqualsStrategyClass() {
return equalsStrategyClass;
}
public JExpression createEqualsStrategy(JCodeModel codeModel) {
return StrategyClassUtils.createStrategyInstanceExpression(codeModel,
EqualsStrategy.class, getEqualsStrategyClass());
}
private Ignoring ignoring = new CustomizedIgnoring(
org.jvnet.jaxb2_commons.plugin.equals.Customizations.IGNORED_ELEMENT_NAME,
Customizations.IGNORED_ELEMENT_NAME,
Customizations.GENERATED_ELEMENT_NAME);
public Ignoring getIgnoring() {
return ignoring;
}
public void setIgnoring(Ignoring ignoring) {
this.ignoring = ignoring;
}
@Override
public Collection<QName> getCustomizationElementNames() {
return Arrays
.asList(org.jvnet.jaxb2_commons.plugin.equals.Customizations.IGNORED_ELEMENT_NAME,
Customizations.IGNORED_ELEMENT_NAME,
Customizations.GENERATED_ELEMENT_NAME);
}
@Override
public boolean run(Outline outline, Options opt, ErrorHandler errorHandler) {
for (final ClassOutline classOutline : outline.getClasses()) {
if (!getIgnoring().isIgnored(classOutline)) {
processClassOutline(classOutline);
}
}
// for (final EnumOutline enumOutline : outline.getEnums()) {
// if (!getIgnoring().isIgnored(enumOutline)) {
// processEnumOutline(enumOutline);
// }
// }
return true;
}
protected void processClassOutline(ClassOutline classOutline) {
final JDefinedClass theClass = classOutline.implClass;
ClassUtils._implements(theClass, theClass.owner().ref(Equals.class));
// @SuppressWarnings("unused")
// final JMethod equals0 = generateEquals$Equals0(classOutline,
// theClass);
@SuppressWarnings("unused")
final JMethod equals = generateEquals$equals(classOutline, theClass);
@SuppressWarnings("unused")
final JMethod objectEquals = generateObject$equals(classOutline,
theClass);
}
// protected void processEnumOutline(EnumOutline enumOutline) {
// final JDefinedClass theClass = enumOutline.clazz;
// ClassUtils._implements(theClass, theClass.owner().ref(Equals.class));
//
// @SuppressWarnings("unused")
// final JMethod equals$equals = generateEquals$equals(enumOutline,
// theClass);
// }
protected JMethod generateObject$equals(final ClassOutline classOutline,
final JDefinedClass theClass) {
final JCodeModel codeModel = theClass.owner();
final JMethod objectEquals = theClass.method(JMod.PUBLIC,
codeModel.BOOLEAN, "equals");
{
final JVar object = objectEquals.param(Object.class, "object");
final JBlock body = objectEquals.body();
final JVar equalsStrategy = body.decl(JMod.FINAL,
codeModel.ref(EqualsStrategy.class), "strategy",
createEqualsStrategy(codeModel));
body._return(JExpr.invoke("equals").arg(JExpr._null())
.arg(JExpr._null()).arg(object).arg(equalsStrategy));
}
return objectEquals;
}
// protected JMethod generateEquals$Equals0(final ClassOutline classOutline,
// final JDefinedClass theClass) {
// final JMethod equalsEquals0 = theClass.method(JMod.PUBLIC, theClass
// .owner().BOOLEAN, "equals");
// {
// final JVar object = equalsEquals0.param(Object.class, "object");
// final JVar equalsStrategy = equalsEquals0.param(
// EqualsStrategy.class, "strategy");
// final JBlock body = equalsEquals0.body();
//
// body._return(JExpr.invoke("equals").arg(JExpr._null()).arg(
// JExpr._null()).arg(object).arg(equalsStrategy));
// }
// return equalsEquals0;
// }
protected JMethod generateEquals$equals(ClassOutline classOutline,
final JDefinedClass theClass) {
final JCodeModel codeModel = theClass.owner();
final JMethod equals = theClass.method(JMod.PUBLIC, codeModel.BOOLEAN,
"equals");
{
final JBlock body = equals.body();
final JVar leftLocator = equals.param(ObjectLocator.class,
"thisLocator");
final JVar rightLocator = equals.param(ObjectLocator.class,
"thatLocator");
final JVar object = equals.param(Object.class, "object");
final JVar equalsStrategy = equals.param(EqualsStrategy.class,
"strategy");
final JConditional ifNotInstanceof = body._if(JOp.not(object
._instanceof(theClass)));
ifNotInstanceof._then()._return(JExpr.FALSE);
//
body._if(JExpr._this().eq(object))._then()._return(JExpr.TRUE);
final Boolean superClassImplementsEquals = StrategyClassUtils
.superClassImplements(classOutline, getIgnoring(),
Equals.class);
if (superClassImplementsEquals == null) {
// No superclass
} else if (superClassImplementsEquals.booleanValue()) {
body._if(
JOp.not(JExpr._super().invoke("equals")
.arg(leftLocator).arg(rightLocator).arg(object)
.arg(equalsStrategy)))._then()
._return(JExpr.FALSE);
} else {
body._if(JOp.not(JExpr._super().invoke("equals").arg(object)))
._then()._return(JExpr.FALSE);
}
final JExpression _this = JExpr._this();
final FieldOutline[] declaredFields = FieldOutlineUtils.filter(
classOutline.getDeclaredFields(), getIgnoring());
if (declaredFields.length > 0) {
final JVar _that = body.decl(JMod.FINAL, theClass, "that",
JExpr.cast(theClass, object));
for (final FieldOutline fieldOutline : declaredFields) {
final FieldAccessorEx leftFieldAccessor = getFieldAccessorFactory()
.createFieldAccessor(fieldOutline, _this);
final FieldAccessorEx rightFieldAccessor = getFieldAccessorFactory()
.createFieldAccessor(fieldOutline, _that);
if (leftFieldAccessor.isConstant()
|| rightFieldAccessor.isConstant()) {
continue;
}
final JBlock block = body.block();
final String name = fieldOutline.getPropertyInfo().getName(
true);
final JVar lhsValue = block.decl(
leftFieldAccessor.getType(), "lhs" + name);
leftFieldAccessor.toRawValue(block, lhsValue);
final JVar rhsValue = block.decl(
rightFieldAccessor.getType(), "rhs" + name);
rightFieldAccessor.toRawValue(block, rhsValue);
final JExpression leftFieldLocator = codeModel
.ref(LocatorUtils.class).staticInvoke("property")
.arg(leftLocator)
.arg(fieldOutline.getPropertyInfo().getName(false))
.arg(lhsValue);
final JExpression rightFieldLocator = codeModel
.ref(LocatorUtils.class).staticInvoke("property")
.arg(rightLocator)
.arg(fieldOutline.getPropertyInfo().getName(false))
.arg(rhsValue);
block._if(
JOp.not(JExpr.invoke(equalsStrategy, "equals")
.arg(leftFieldLocator)
.arg(rightFieldLocator).arg(lhsValue)
.arg(rhsValue)))._then()
._return(JExpr.FALSE);
}
}
body._return(JExpr.TRUE);
}
return equals;
}
// protected JMethod generateEquals$equals(EnumOutline enumOutline,
// final JDefinedClass theClass) {
//
// final JCodeModel codeModel = theClass.owner();
// final JMethod equals = theClass.method(JMod.PUBLIC, codeModel.BOOLEAN,
// "equals");
//
// {
// final JBlock body = equals.body();
// final JVar leftLocator = equals.param(ObjectLocator.class,
// "thisLocator");
// final JVar rightLocator = equals.param(ObjectLocator.class,
// "thatLocator");
// final JVar object = equals.param(Object.class, "object");
// final JVar equalsStrategy = equals.param(EqualsStrategy.class,
// "strategy");
//
// body._return(equalsStrategy
// .invoke("equals")
// .arg(codeModel.ref(LocatorUtils.class)
// .staticInvoke("property").arg(leftLocator)
// .arg("value").arg(JExpr._this().ref("value")))
// .arg(codeModel.ref(LocatorUtils.class)
// .staticInvoke("property").arg(rightLocator)
// .arg("value").arg(object.ref("value")))
// .arg(JExpr._this().ref("value")).arg(object.ref("value")));
//
// }
// return equals;
// }
}