Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.polyglotted.xpathstax.bind.XmlBinderContext Maven / Gradle / Ivy
package org.polyglotted.xpathstax.bind;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Maps.newHashMap;
import static org.polyglotted.xpathstax.bind.ReflUtil.*;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Stack;
import javax.annotation.concurrent.NotThreadSafe;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlValue;
import org.polyglotted.xpathstax.data.Value;
import org.polyglotted.xpathstax.model.XmlNode;
import com.google.common.annotations.VisibleForTesting;
@NotThreadSafe
class XmlBinderContext {
private final Class rootClass;
private final String rootName;
private final Map> types = newHashMap();
private final Map, ClassContext> contexts = newHashMap();
private final Stack nameStack = new Stack();
private final Stack newObjects = new Stack();
public XmlBinderContext(Class tClass) {
rootClass = validateRoot(tClass);
rootName = getRootElementName(rootClass);
build(rootName, rootClass);
}
private void build(String fieldName, Class> clazz) {
final ClassContext ctx = new ClassContext();
types.put(fieldName, clazz);
contexts.put(clazz, ctx);
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(XmlValue.class)) {
checkBasicClass(field.getType(), field.getName());
ctx.setXmlValueField(field);
} else if (field.isAnnotationPresent(XmlAttribute.class)) {
if (!isEnumType(field.getType()))
checkBasicClass(field.getType(), field.getName());
ctx.addAttribute(field);
} else if (field.isAnnotationPresent(XmlElement.class)) {
Class> fieldClass = getFieldClass(field);
if (isXmlType(fieldClass)) {
build(getElementName(field), fieldClass);
} else {
if (!isEnumType(fieldClass))
checkBasicClass(fieldClass, field.getName());
}
if (isCollection(field)) {
ctx.addCollection(field);
} else {
ctx.addElement(field);
}
}
}
}
private void checkBasicClass(Class> clazz, String fieldName) {
checkArgument(isBasicClass(clazz), fieldName + " is not a primitive or String");
}
private boolean isXmlType(Class> fieldClass) {
return fieldClass.isAnnotationPresent(XmlType.class);
}
private boolean isEnumType(Class> fieldClass) {
return fieldClass.isEnum() && fieldClass.isAnnotationPresent(XmlEnum.class);
}
public void elementStart(String element) {
if (types.containsKey(element)) {
nameStack.push(element);
newObjects.push(createNewData(types.get(element)));
}
}
public T retrieve(XmlNode node) {
checkArgument(rootName.equals(node.getName()));
Object rootObject = newObjects.pop();
setAttributesAndXmlValue(rootObject, node, contexts.get(rootClass));
return rootClass.cast(rootObject);
}
public void handleChildNode(XmlNode child) {
String childName = child.getName();
Object childObj = null;
if (types.containsKey(childName)) {
checkArgument(childName.equals(nameStack.pop()));
childObj = newObjects.pop();
setAttributesAndXmlValue(childObj, child, contexts.get(types.get(childName)));
}
ClassContext prevCtx = contexts.get(types.get(nameStack.peek()));
Object prevObject = newObjects.peek();
if (childObj == null) {
prevCtx.putValue(prevObject, childName, child.getText());
} else {
prevCtx.putChild(prevObject, childName, childObj);
}
}
private void setAttributesAndXmlValue(Object object, XmlNode node, ClassContext context) {
context.putXmlValue(object, node.getText());
for (Map.Entry entry : node.getAttribute().iterate()) {
context.putValue(object, entry.getKey(), entry.getValue());
}
}
@VisibleForTesting
Map> getTypes() {
return types;
}
@VisibleForTesting
Map, ClassContext> getContexts() {
return contexts;
}
@VisibleForTesting
static class ClassContext {
final Map attributes = newHashMap();
final Map elements = newHashMap();
final Map collections = newHashMap();
private Field xmlValueField = null;
void addAttribute(Field field) {
field.setAccessible(true);
attributes.put(getAttributeName(field), field);
}
void addElement(Field field) {
field.setAccessible(true);
elements.put(getElementName(field), field);
}
void addCollection(Field field) {
field.setAccessible(true);
collections.put(getElementName(field), field);
}
void putValue(Object lastObject, String fieldName, Value value) {
if (elements.containsKey(fieldName)) {
putPrimitiveValue(lastObject, value, elements.get(fieldName));
} else if (collections.containsKey(fieldName)) {
putPrimitiveInCollection(lastObject, value, collections.get(fieldName));
} else if (attributes.containsKey(fieldName)) {
putPrimitiveValue(lastObject, value, attributes.get(fieldName));
}
}
void putChild(Object lastObject, String fieldName, Object child) {
if (elements.containsKey(fieldName)) {
putChildObject(lastObject, child, elements.get(fieldName));
} else if (collections.containsKey(fieldName)) {
putChildInCollection(lastObject, child, collections.get(fieldName));
}
}
void putXmlValue(Object object, Value value) {
if (xmlValueField != null)
putPrimitiveValue(object, value, xmlValueField);
}
void setXmlValueField(Field field) {
field.setAccessible(true);
this.xmlValueField = field;
}
Field getXmlValueField() {
return xmlValueField;
}
}
}