package org.jvnet.jaxb2_commons.plugin.tostring; import java.util.Arrays; import java.util.Collection; import javax.xml.namespace.QName; import org.jvnet.jaxb2_commons.lang.JAXBToStringStrategy; import org.jvnet.jaxb2_commons.lang.ToString; import org.jvnet.jaxb2_commons.lang.ToStringStrategy; import org.jvnet.jaxb2_commons.locator.ObjectLocator; 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 ToStringPlugin extends AbstractParameterizablePlugin { @Override public String getOptionName() { return "XtoString"; } @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 toStringStrategyClass = JAXBToStringStrategy.class.getName(); public void setToStringStrategyClass( String toStringStrategy) { this.toStringStrategyClass = toStringStrategy; } public String getToStringStrategyClass() { return toStringStrategyClass; } public JExpression createToStringStrategy(JCodeModel codeModel) { return StrategyClassUtils.createStrategyInstanceExpression(codeModel, ToStringStrategy.class, getToStringStrategyClass()); } private Ignoring ignoring = new CustomizedIgnoring( org.jvnet.jaxb2_commons.plugin.tostring.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.tostring.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); } return true; } protected void processClassOutline(ClassOutline classOutline) { final JDefinedClass theClass = classOutline.implClass; ClassUtils._implements(theClass, theClass.owner().ref(ToString.class)); @SuppressWarnings("unused") final JMethod object$toString = generateObject$toString(classOutline, theClass); @SuppressWarnings("unused") final JMethod toString$append = generateToString$append(classOutline, theClass); @SuppressWarnings("unused") final JMethod toString$appendFields = generateToString$appendFields( classOutline, theClass); } protected JMethod generateObject$toString(final ClassOutline classOutline, final JDefinedClass theClass) { final JCodeModel codeModel = theClass.owner(); final JMethod object$toString = theClass.method(JMod.PUBLIC, codeModel .ref(String.class), "toString"); { final JBlock body = object$toString.body(); final JVar toStringStrategy = body.decl(JMod.FINAL, codeModel.ref(ToStringStrategy.class), "strategy", createToStringStrategy(codeModel)); final JVar buffer = body.decl(JMod.FINAL, codeModel .ref(StringBuilder.class), "buffer", JExpr._new(codeModel .ref(StringBuilder.class))); body.invoke("append").arg(JExpr._null()).arg(buffer).arg( toStringStrategy); body._return(buffer.invoke("toString")); } return object$toString; } protected JMethod generateToString$append(final ClassOutline classOutline, final JDefinedClass theClass) { final JCodeModel codeModel = theClass.owner(); final JMethod toString$append = theClass.method(JMod.PUBLIC, codeModel .ref(StringBuilder.class), "append"); { final JVar locator = toString$append.param(ObjectLocator.class, "locator"); final JVar buffer = toString$append.param(StringBuilder.class, "buffer"); final JVar toStringStrategy = toString$append.param( ToStringStrategy.class, "strategy"); final JBlock body = toString$append.body(); body.invoke(toStringStrategy, "appendStart").arg(locator).arg( JExpr._this()).arg(buffer); body.invoke("appendFields").arg(locator).arg(buffer).arg( toStringStrategy); body.invoke(toStringStrategy, "appendEnd").arg(locator).arg( JExpr._this()).arg(buffer); body._return(buffer); } return toString$append; } protected JMethod generateToString$appendFields(ClassOutline classOutline, final JDefinedClass theClass) { final JCodeModel codeModel = theClass.owner(); final JMethod toString$appendFields = theClass.method(JMod.PUBLIC, codeModel.ref(StringBuilder.class), "appendFields"); { final JVar locator = toString$appendFields.param( ObjectLocator.class, "locator"); final JVar buffer = toString$appendFields.param( StringBuilder.class, "buffer"); final JVar toStringStrategy = toString$appendFields.param( ToStringStrategy.class, "strategy"); final JBlock body = toString$appendFields.body(); final Boolean superClassImplementsToString = StrategyClassUtils .superClassImplements(classOutline, ignoring, ToString.class); if (superClassImplementsToString == null) { // No superclass } else if (superClassImplementsToString.booleanValue()) { body.invoke(JExpr._super(), "appendFields").arg(locator).arg( buffer).arg(toStringStrategy); } else { // Superclass does not implement ToString } final FieldOutline[] declaredFields = FieldOutlineUtils.filter( classOutline.getDeclaredFields(), getIgnoring()); if (declaredFields.length > 0) { for (final FieldOutline fieldOutline : declaredFields) { final JBlock block = body.block(); final FieldAccessorEx fieldAccessor = getFieldAccessorFactory() .createFieldAccessor(fieldOutline, JExpr._this()); final JVar theValue = block.decl(fieldAccessor.getType(), "the" + fieldOutline.getPropertyInfo().getName( true)); fieldAccessor.toRawValue(block, theValue); block.invoke(toStringStrategy, "appendField").arg(locator) .arg(JExpr._this()).arg( JExpr.lit(fieldOutline.getPropertyInfo() .getName(false))).arg(buffer).arg( theValue); } } body._return(buffer); } return toString$appendFields; } }