package org.jvnet.jaxb2_commons.plugin.hashcode;
import java.util.Arrays;
import java.util.Collection;
import javax.xml.namespace.QName;
import org.jvnet.jaxb2_commons.lang.HashCode;
import org.jvnet.jaxb2_commons.lang.HashCodeStrategy;
import org.jvnet.jaxb2_commons.lang.JAXBHashCodeStrategy;
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.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.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 HashCodePlugin extends AbstractParameterizablePlugin {
@Override
public String getOptionName() {
return "XhashCode";
}
@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 hashCodeStrategyClass = JAXBHashCodeStrategy.class.getName();
public void setHashCodeStrategyClass(String hashCodeStrategy) {
this.hashCodeStrategyClass = hashCodeStrategy;
}
public String getHashCodeStrategyClass() {
return hashCodeStrategyClass;
}
public JExpression createHashCodeStrategy(JCodeModel codeModel) {
return StrategyClassUtils.createStrategyInstanceExpression(codeModel,
HashCodeStrategy.class, getHashCodeStrategyClass());
}
private Ignoring ignoring = new CustomizedIgnoring(
org.jvnet.jaxb2_commons.plugin.hashcode.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.hashcode.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(HashCode.class));
// @SuppressWarnings("unused")
// final JMethod hashCode$hashCode0 = generateHashCode$hashCode0(
// classOutline, theClass);
@SuppressWarnings("unused")
final JMethod hashCode$hashCode = generateHashCode$hashCode(
classOutline, theClass);
@SuppressWarnings("unused")
final JMethod object$hashCode = generateObject$hashCode(classOutline,
theClass);
}
// protected void processEnumOutline(EnumOutline enumOutline) {
// final JDefinedClass theClass = enumOutline.clazz;
// ClassUtils._implements(theClass, theClass.owner().ref(HashCode.class));
//
// // @SuppressWarnings("unused")
// // final JMethod hashCode$hashCode0 = generateHashCode$hashCode0(
// // classOutline, theClass);
// @SuppressWarnings("unused")
// final JMethod hashCode$hashCode = generateHashCode$hashCode(
// enumOutline, theClass);
// // @SuppressWarnings("unused")
// // final JMethod object$hashCode = generateObject$hashCode(enumOutline,
// // theClass);
// }
protected JMethod generateObject$hashCode(final ClassOutline classOutline,
final JDefinedClass theClass) {
return generateObject$hashCode(theClass);
}
// protected JMethod generateObject$hashCode(final EnumOutline enumOutline,
// final JDefinedClass theClass) {
// return generateObject$hashCode(theClass);
// }
private JMethod generateObject$hashCode(final JDefinedClass theClass) {
final JMethod object$hashCode = theClass.method(JMod.PUBLIC,
theClass.owner().INT, "hashCode");
{
final JBlock body = object$hashCode.body();
final JVar hashCodeStrategy = body.decl(JMod.FINAL, theClass
.owner().ref(HashCodeStrategy.class), "strategy",
createHashCodeStrategy(theClass.owner()));
body._return(JExpr._this().invoke("hashCode").arg(JExpr._null())
.arg(hashCodeStrategy));
}
return object$hashCode;
}
protected JMethod generateHashCode$hashCode(ClassOutline classOutline,
final JDefinedClass theClass) {
JCodeModel codeModel = theClass.owner();
final JMethod hashCode$hashCode = theClass.method(JMod.PUBLIC,
codeModel.INT, "hashCode");
{
final JVar locator = hashCode$hashCode.param(ObjectLocator.class,
"locator");
final JVar hashCodeStrategy = hashCode$hashCode.param(
HashCodeStrategy.class, "strategy");
final JBlock body = hashCode$hashCode.body();
final JExpression currentHashCodeExpression;
final Boolean superClassImplementsHashCode = StrategyClassUtils
.superClassImplements(classOutline, ignoring,
HashCode.class);
if (superClassImplementsHashCode == null) {
currentHashCodeExpression = JExpr.lit(1);
} else if (superClassImplementsHashCode.booleanValue()) {
currentHashCodeExpression = JExpr._super().invoke("hashCode")
.arg(locator).arg(hashCodeStrategy);
} else {
currentHashCodeExpression = JExpr._super().invoke("hashCode");
}
final JVar currentHashCode = body.decl(codeModel.INT,
"currentHashCode", currentHashCodeExpression);
final FieldOutline[] declaredFields = FieldOutlineUtils.filter(
classOutline.getDeclaredFields(), getIgnoring());
if (declaredFields.length > 0) {
for (final FieldOutline fieldOutline : declaredFields) {
final FieldAccessorEx fieldAccessor = getFieldAccessorFactory()
.createFieldAccessor(fieldOutline, JExpr._this());
if (fieldAccessor.isConstant()) {
continue;
}
final JBlock block = body.block();
final JVar theValue = block.decl(
fieldAccessor.getType(),
"the"
+ fieldOutline.getPropertyInfo().getName(
true));
fieldAccessor.toRawValue(block, theValue);
block.assign(
currentHashCode,
hashCodeStrategy
.invoke("hashCode")
.arg(codeModel
.ref(LocatorUtils.class)
.staticInvoke("property")
.arg(locator)
.arg(fieldOutline.getPropertyInfo()
.getName(false))
.arg(theValue))
.arg(currentHashCode).arg(theValue));
}
}
body._return(currentHashCode);
}
return hashCode$hashCode;
}
// protected JMethod generateHashCode$hashCode(EnumOutline enumOutline,
// final JDefinedClass theClass) {
//
// JCodeModel codeModel = theClass.owner();
// final JMethod hashCode$hashCode = theClass.method(JMod.PUBLIC,
// codeModel.INT, "hashCode");
// final JVar locator = hashCode$hashCode.param(ObjectLocator.class,
// "locator");
// final JVar hashCodeStrategy = hashCode$hashCode.param(
// HashCodeStrategy.class, "strategy");
// final JBlock body = hashCode$hashCode.body();
//
// body._return(hashCodeStrategy
// .invoke("hashCode")
// .arg(codeModel.ref(LocatorUtils.class).staticInvoke("property")
// .arg(locator).arg("value")
// .arg(JExpr._this().ref("value"))).arg(JExpr.lit(1))
// .arg(JExpr._this().ref("value")));
//
// return hashCode$hashCode;
// }
}