package org.jvnet.jaxb2_commons.util;
import org.jvnet.jaxb2_commons.xjc.outline.FieldAccessorEx;
import com.sun.codemodel.JBlock;
import com.sun.codemodel.JConditional;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JExpr;
import com.sun.codemodel.JExpression;
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
import com.sun.codemodel.JOp;
import com.sun.codemodel.JType;
import com.sun.codemodel.JVar;
import com.sun.tools.xjc.model.CPropertyInfo;
import com.sun.tools.xjc.outline.FieldAccessor;
import com.sun.tools.xjc.outline.FieldOutline;
public class PropertyFieldAccessorFactory implements FieldAccessorFactory {
public static FieldAccessorFactory INSTANCE = new PropertyFieldAccessorFactory();
public PropertyFieldAccessorFactory() {
}
public FieldAccessorEx createFieldAccessor(FieldOutline fieldOutline,
JExpression targetObject) {
return new PropertyFieldAccessor(fieldOutline, targetObject);
}
private static class PropertyFieldAccessor implements FieldAccessorEx {
private static final JType[] ABSENT = new JType[0];
private final FieldOutline fieldOutline;
private final JExpression targetObject;
private final JDefinedClass theClass;
private final JMethod isSetter;
private final JMethod unSetter;
private final JMethod getter;
private final JMethod setter;
private final JFieldVar constantField;
private FieldAccessor fieldAccessor;
private final JType type;
public PropertyFieldAccessor(final FieldOutline fieldOutline,
JExpression targetObject) {
super();
this.fieldOutline = fieldOutline;
this.targetObject = targetObject;
this.fieldAccessor = fieldOutline.create(targetObject);
final String publicName = fieldOutline.getPropertyInfo().getName(
true);
this.theClass = fieldOutline.parent().implClass;
final String setterName = "set" + publicName;
final JMethod getGetter = theClass.getMethod("get" + publicName,
ABSENT);
final JMethod isGetter = theClass.getMethod("is" + publicName,
ABSENT);
this.getter = getGetter != null ? getGetter
: (isGetter != null ? isGetter : null);
this.type = this.getter != null ? this.getter.type() : fieldOutline
.getRawType();
final JFieldVar field = theClass.fields().get(publicName);
this.constantField = field != null
&& ((field.mods().getValue() & JMod.PUBLIC) != 0)
&& ((field.mods().getValue() & JMod.STATIC) != 0)
&& ((field.mods().getValue() & JMod.FINAL) != 0) ? field
: null;
// fieldOutline.getRawType();
final JType rawType = fieldOutline.getRawType();
final JMethod boxifiedSetter = theClass.getMethod(setterName,
new JType[] { rawType.boxify() });
final JMethod unboxifiedSetter = theClass.getMethod(setterName,
new JType[] { rawType.unboxify() });
this.setter = boxifiedSetter != null ? boxifiedSetter
: unboxifiedSetter;
this.isSetter = theClass.getMethod("isSet" + publicName, ABSENT);
this.unSetter = theClass.getMethod("unset" + publicName, ABSENT);
}
public JType getType() {
return type;
}
public boolean isVirtual() {
return constantField != null;
}
public boolean isConstant() {
return constantField != null;
}
public FieldOutline owner() {
return fieldOutline;
}
public CPropertyInfo getPropertyInfo() {
return fieldOutline.getPropertyInfo();
}
public boolean isAlwaysSet() {
if (constantField != null) {
return true;
} else {
return JExpr.TRUE == fieldAccessor.hasSetValue();
}
}
public JExpression hasSetValue() {
if (constantField != null) {
return JExpr.TRUE;
} else if (isSetter != null) {
return targetObject.invoke(isSetter);
} else {
return fieldAccessor.hasSetValue();
}
}
public void unsetValues(JBlock body) {
if (constantField != null) {
} else if (unSetter != null) {
body.invoke(targetObject, unSetter);
} else {
fieldAccessor.unsetValues(body);
}
}
public void fromRawValue(JBlock block, String uniqueName,
JExpression $var) {
if (constantField != null) {
} else if (setter != null) {
block.invoke(targetObject, setter).arg($var);
} else {
unsetValues(block);
if (fieldOutline.getPropertyInfo().isCollection()) {
fieldAccessor.fromRawValue(block
._if($var.ne(JExpr._null()))._then(), uniqueName,
$var);
} else {
fieldAccessor.fromRawValue(block, uniqueName, $var);
}
}
}
public void toRawValue(JBlock block, JVar $var) {
if (constantField != null) {
block.assign($var, theClass.staticRef(this.constantField));
} else if (type.isPrimitive()
|| fieldOutline.getPropertyInfo().isCollection()) {
final JExpression defaultExpression;
if (type.isPrimitive()) {
if (type.fullName().equals(type.owner().BOOLEAN.fullName())) {
defaultExpression = JExpr.FALSE;
} else if (type.fullName().equals(
type.owner().BYTE.fullName())) {
final byte value = 0;
defaultExpression = JExpr.lit(value);
} else if (type.fullName().equals(
type.owner().CHAR.fullName())) {
final char value = 0;
defaultExpression = JExpr.lit(value);
} else if (type.fullName().equals(
type.owner().DOUBLE.fullName())) {
final double value = 0;
defaultExpression = JExpr.lit(value);
} else if (type.fullName().equals(
type.owner().FLOAT.fullName())) {
final float value = 0;
defaultExpression = JExpr.lit(value);
} else if (type.fullName().equals(
type.owner().INT.fullName())) {
final int value = 0;
defaultExpression = JExpr.lit(value);
} else if (type.fullName().equals(
type.owner().LONG.fullName())) {
final long value = 0;
defaultExpression = JExpr.lit(value);
} else if (type.fullName().equals(
type.owner().SHORT.fullName())) {
final short value = 0;
defaultExpression = JExpr.lit(value);
} else {
throw new UnsupportedOperationException();
}
} else if (fieldOutline.getPropertyInfo().isCollection()) {
defaultExpression = JExpr._null();
} else {
throw new UnsupportedOperationException();
}
if (getter != null) {
if (isAlwaysSet()) {
block.assign($var, targetObject.invoke(getter));
} else {
block.assign($var, JOp.cond(hasSetValue(),
targetObject.invoke(getter), defaultExpression));
}
} else {
final JConditional _if = block._if(hasSetValue());
fieldAccessor.toRawValue(_if._then(), $var);
_if._else().assign($var, defaultExpression);
}
} else {
if (getter != null) {
block.assign($var, targetObject.invoke(getter));
} else {
fieldAccessor.toRawValue(block, $var);
}
}
}
}
}