public final class ElementDescriptor<T>
{
	public final static XmlContext DEFAULT_CONTEXT = new XmlContext()
	{
	};

	/**
	 * The {@link QualifiedName} of this element.
	 */
	public final QualifiedName qualifiedName;

	/**
	 * An {@link IObjectBuilder} for elements of this type.
	 */
	public final IObjectBuilder<T> builder;

	/**
	 * A {@link WeakReference} to the context this element was registered in.
	 */
	private final WeakReference<XmlContext> mContext;

	/**
	 * A synchronized map of {@link QualifiedName}s to {@link ElementDescriptor}s of Elements valid in the context of this element. May be <code>null</code>.
	 */
	private Map<QualifiedName, ElementDescriptor<?>> mElementContext;


	/**
	 * Return the {@link ElementDescriptor} of the element having the given {@link QualifiedName} from the default {@link XmlContext}.
	 * 
	 * @param qname
	 *            The {@link QualifiedName} of the {@link ElementDescriptor} to return.
	 * @return The {@link ElementDescriptor} or <code>null</code> if there is no such element in the default {@link XmlContext}.
	 */
	public static ElementDescriptor<?> get(QualifiedName qname)
	{
		synchronized (DEFAULT_CONTEXT)
		{
			return DEFAULT_CONTEXT.DESCRIPTOR_MAP.get(qname);
		}
	}


	/**
	 * Return the {@link ElementDescriptor} of the element having the given {@link QualifiedName} from the given {@link XmlContext}.
	 * 
	 * @param qname
	 *            The {@link QualifiedName} of the {@link ElementDescriptor} to return.
	 * @param context
	 *            The {@link XmlContext}.
	 * @return The {@link ElementDescriptor} or <code>null</code> if there is no such element in the given {@link XmlContext}.
	 */
	public static ElementDescriptor<?> get(QualifiedName qname, XmlContext context)
	{
		if (context == null)
		{
			context = DEFAULT_CONTEXT;
		}

		synchronized (context)
		{
			final Map<QualifiedName, ElementDescriptor<?>> contextMap = context.DESCRIPTOR_MAP;
			ElementDescriptor<?> result = contextMap.get(qname);
			if (result != null)
			{
				return result;
			}
		}

		synchronized (DEFAULT_CONTEXT)
		{
			return DEFAULT_CONTEXT.DESCRIPTOR_MAP.get(qname);
		}
	}


	/**
	 * Return the {@link ElementDescriptor} of the element having the given {@link QualifiedName}. This method returns first checks the context of the given
	 * parent {@link ElementDescriptor} for matching element and falls back to the default {@link XmlContext}if no matching element is found in the parent
	 * context.
	 * 
	 * @param qname
	 *            The {@link QualifiedName} of the {@link ElementDescriptor} to return.
	 * @param parentElement
	 *            The parent {@link ElementDescriptor}.
	 * @return The {@link ElementDescriptor} or <code>null</code> if there is no such element in the parent context of the default {@link XmlContext}.
	 */
	public static ElementDescriptor<?> get(QualifiedName qname, ElementDescriptor<?> parentElement)
	{
		if (parentElement == null || parentElement.mElementContext == null)
		{
			return get(qname);
		}

		ElementDescriptor<?> result = parentElement.mElementContext.get(qname);
		return result == null ? get(qname) : result;
	}


	/**
	 * Return the {@link ElementDescriptor} of the element having the given {@link QualifiedName}. This method returns first checks the context of the given
	 * parent {@link ElementDescriptor} for matching element and falls back to the given {@link XmlContext}if no matching element is found in the parent
	 * context.
	 * 
	 * @param qname
	 *            The {@link QualifiedName} of the {@link ElementDescriptor} to return.
	 * @param parentElement
	 *            The parent {@link ElementDescriptor}.
	 * @param context
	 *            An {@link XmlContext}, may be <code>null</code> for the default context.
	 * @return The {@link ElementDescriptor} or <code>null</code> if there is no such element in the parent context of the given {@link XmlContext}.
	 */
	public static ElementDescriptor<?> get(QualifiedName qname, ElementDescriptor<?> parentElement, XmlContext context)
	{
		if (parentElement == null || parentElement.mElementContext == null)
		{
			return get(qname, context);
		}

		ElementDescriptor<?> result = parentElement.mElementContext.get(qname);
		return result == null ? get(qname, context) : result;
	}


	/**
	 * Register an element with the given name and no name space using the given {@link IObjectBuilder} in the default {@link XmlContext}.
	 * 
	 * @param name
	 *            The name of the element.
	 * @param builder
	 *            The {@link IObjectBuilder} to build and serialize this element.
	 * @return The {@link ElementDescriptor}.
	 */
	public static <T> ElementDescriptor<T> register(String name, IObjectBuilder<T> builder)
	{
		return register(QualifiedName.get(name), builder, DEFAULT_CONTEXT);
	}


	/**
	 * Register an element with the given {@link QualifiedName} using the given {@link IObjectBuilder} in the default {@link XmlContext}.
	 * 
	 * @param qname
	 *            The {@link QualifiedName} of the element.
	 * @param builder
	 *            The {@link IObjectBuilder} to build and serialize this element.
	 * @return The {@link ElementDescriptor}.
	 */
	public static <T> ElementDescriptor<T> register(QualifiedName qname, IObjectBuilder<T> builder)
	{
		return register(qname, builder, DEFAULT_CONTEXT);
	}


	/**
	 * Register an element with the given name and no name space using the given {@link IObjectBuilder} in the given {@link XmlContext}.
	 * 
	 * @param name
	 *            The name of the element.
	 * @param builder
	 *            The {@link IObjectBuilder} to build and serialize this element.
	 * @param context
	 *            An {@link XmlContext}.
	 * @return The {@link ElementDescriptor}.
	 */
	public static <T> ElementDescriptor<T> register(String name, IObjectBuilder<T> builder, XmlContext context)
	{
		return register(QualifiedName.get(name), builder, context);
	}


	/**
	 * Register an element with the given {@link QualifiedName} using the given {@link IObjectBuilder} in the given {@link XmlContext}.
	 * 
	 * @param qname
	 *            The {@link QualifiedName} of the element.
	 * @param builder
	 *            The {@link IObjectBuilder} to build and serialize this element.
	 * @param context
	 *            An {@link XmlContext} or <code>null</code> to use the default {@link XmlContext}.
	 * @return The {@link ElementDescriptor}.
	 */
	public static <T> ElementDescriptor<T> register(QualifiedName qname, IObjectBuilder<T> builder, XmlContext context)
	{
		if (context == null)
		{
			context = DEFAULT_CONTEXT;
		}

		synchronized (context)
		{
			Map<QualifiedName, ElementDescriptor<?>> descriptorMap = context.DESCRIPTOR_MAP;

			if (descriptorMap.containsKey(qname))
			{
				throw new IllegalStateException("descriptor for " + qname + " already exists, use 'overload' to override the definition");
			}

			ElementDescriptor<T> descriptor = new ElementDescriptor<T>(qname, builder, context);
			descriptorMap.put(qname, descriptor);
			return descriptor;
		}
	}


	/**
	 * Register an element with the given name and no name space using the given {@link IObjectBuilder} in the context of the given parent
	 * {@link ElementDescriptor}s. An element that is registered with this method will not be available in a general {@link XmlContext}, but only when providing
	 * the parent {@link ElementDescriptor} using {@link #get(QualifiedName, ElementDescriptor)} or {@link #get(QualifiedName, ElementDescriptor, XmlContext)}.
	 * <p>
	 * Note: All parents must be registered within in the same {@link XmlContext}.
	 * </p>
	 * 
	 * @param name
	 *            The name of the element.
	 * @param builder
	 *            The {@link IObjectBuilder} to build and serialize this element.
	 * @param parentElements
	 *            The {@link ElementDescriptor}s of the parent elements to register the new element with.
	 * @return The {@link ElementDescriptor}.
	 */
	public static <T> ElementDescriptor<T> registerWithParents(String name, IObjectBuilder<T> builder, ElementDescriptor<?>... parentElements)
	{
		return registerWithParents(QualifiedName.get(name), builder, parentElements);
	}


	/**
	 * Register an element with the given {@link QualifiedName} using the given {@link IObjectBuilder} in the context of the given parent
	 * {@link ElementDescriptor}s. An element that is registered with this method will not be available in a general {@link XmlContext}, but only when providing
	 * the parent {@link ElementDescriptor} using {@link #get(QualifiedName, ElementDescriptor)} or {@link #get(QualifiedName, ElementDescriptor, XmlContext)}.
	 * <p>
	 * Note: All parents must be registered within in the same {@link XmlContext}.
	 * </p>
	 * 
	 * @param qname
	 *            The {@link QualifiedName} of the element.
	 * @param builder
	 *            The {@link IObjectBuilder} to build and serialize this element.
	 * @param parentElements
	 *            The {@link ElementDescriptor}s of the parent elements to register the new element with.
	 * @return The {@link ElementDescriptor}.
	 */
	public static <T> ElementDescriptor<T> registerWithParents(QualifiedName qname, IObjectBuilder<T> builder, ElementDescriptor<?>... parentElements)
	{
		if (parentElements == null || parentElements.length == 0)
		{
			throw new IllegalArgumentException("no parent elements provided");
		}

		// create the new descriptor with the context of the first parent
		ElementDescriptor<T> descriptor = new ElementDescriptor<T>(qname, builder, parentElements[0].getContext());

		// register the descriptor with all parents
		for (ElementDescriptor<?> parentElement : parentElements)
		{
			if (descriptor.getContext() != parentElement.getContext())
			{
				throw new IllegalArgumentException("Parent descriptors don't belong to the same XmlContext");
			}
			Map<QualifiedName, ElementDescriptor<?>> descriptorMap = parentElement.mElementContext;

			if (descriptorMap == null)
			{
				descriptorMap = parentElement.mElementContext = Collections.synchronizedMap(new HashMap<QualifiedName, ElementDescriptor<?>>(8));
			}
			else if (descriptorMap.containsKey(qname))
			{
				throw new IllegalStateException("descriptor for " + qname + " already exists in parent " + parentElement.qualifiedName);
			}

			descriptorMap.put(qname, descriptor);
		}
		return descriptor;
	}


	public static <T> ElementDescriptor<T> overload(ElementDescriptor<? super T> oldDescriptor, IObjectBuilder<T> builder)
	{
		XmlContext context = oldDescriptor.mContext.get();
		if (context == null)
		{
			throw new IllegalStateException("can not overload element in gc'ed context");
		}

		synchronized (context)
		{
			Map<QualifiedName, ElementDescriptor<?>> descriptorMap = context.DESCRIPTOR_MAP;
			QualifiedName qname = oldDescriptor.qualifiedName;
			ElementDescriptor<T> descriptor = new ElementDescriptor<T>(qname, builder, context);

			// both elements have the same child descriptors, if any
			descriptor.mElementContext = oldDescriptor.mElementContext;
			descriptorMap.put(qname, descriptor);
			return descriptor;
		}
	}


	private ElementDescriptor(QualifiedName qname, IObjectBuilder<T> builder, XmlContext context)
	{
		if (qname == null)
		{
			throw new IllegalArgumentException("qname must not be null");
		}

		this.qualifiedName = qname;
		this.builder = builder;
		this.mContext = new WeakReference<XmlContext>(context);
	}


	public XmlContext getContext()
	{
		return mContext.get();
	}


	@Override
	public int hashCode()
	{
		return qualifiedName.hashCode();
	}


	@Override
	public boolean equals(Object o)
	{
		return o == this;
	}
} public final class QualifiedName
{
	/**
	 * A cache of all known {@link QualifiedName}s. This is a map of namespaces to a map of names (in the respective name space) to the {@link QualifiedName}
	 * object.
	 */
	private final static Map<String, Map<String, QualifiedName>> QUALIFIED_NAME_CACHE = new HashMap<String, Map<String, QualifiedName>>(64);

	/**
	 * The namespace of this qualified name.
	 */
	public final String namespace;

	/**
	 * The name part of this qualified name.
	 */
	public final String name;

	/**
	 * The cached hash code.
	 */
	private final int mHashCode;


	/**
	 * Returns a {@link QualifiedName} with an empty name space. If the {@link QualifiedName} already exists, the existing instance is returned, otherwise it's
	 * created.
	 * 
	 * @param name
	 *            The name of the {@link QualifiedName}.
	 * @return The {@link QualifiedName} instance.
	 */
	public static QualifiedName get(String name)
	{
		return get(null, name);
	}


	/**
	 * Returns a {@link QualifiedName} with a specific name space. If the {@link QualifiedName} already exists, the existing instance is returned, otherwise
	 * it's created.
	 * 
	 * @param namespace
	 *            The namespace of the {@link QualifiedName}.
	 * @param name
	 *            The name of the {@link QualifiedName}.
	 * @return The {@link QualifiedName} instance.
	 */
	public static QualifiedName get(String namespace, String name)
	{
		if (namespace != null && namespace.length() == 0)
		{
			namespace = null;
		}

		synchronized (QUALIFIED_NAME_CACHE)
		{
			Map<String, QualifiedName> qualifiedNameMap = QUALIFIED_NAME_CACHE.get(namespace);
			QualifiedName qualifiedName;
			if (qualifiedNameMap == null)
			{
				qualifiedNameMap = new HashMap<String, QualifiedName>();
				qualifiedName = new QualifiedName(namespace, name);
				qualifiedNameMap.put(name, qualifiedName);
				QUALIFIED_NAME_CACHE.put(namespace, qualifiedNameMap);
			}
			else
			{
				qualifiedName = qualifiedNameMap.get(name);
				if (qualifiedName == null)
				{
					qualifiedName = new QualifiedName(namespace, name);
					qualifiedNameMap.put(name, qualifiedName);
				}
			}
			return qualifiedName;
		}
	}


	/**
	 * Instantiate a new {@link QualifiedName} with the given name and namespace.
	 * 
	 * @param namespace
	 *            The namespace of the qualified name.
	 * @param name
	 *            The name part of the qualified name.
	 */
	private QualifiedName(String namespace, String name)
	{
		if (name == null)
		{
			throw new IllegalArgumentException("name part of a qualified name must not be null");
		}

		this.namespace = namespace;
		this.name = name;

		mHashCode = namespace == null ? name.hashCode() : namespace.hashCode() * 31 + name.hashCode();
	}


	@Override
	public int hashCode()
	{
		return mHashCode;
	}


	@Override
	public boolean equals(Object o)
	{
		return o == this;
	}


	@Override
	public String toString()
	{
		return namespace == null ? name : namespace + ":" + name;
	}


	/**
	 * Returns the qualified name in Clark notation.
	 * 
	 * @return A {@link String} representing the qualified name.
	 * 
	 * @see <a href="https://tools.ietf.org/html/draft-saintandre-json-namespaces-00">JavaScript Object Notation (JSON) Namespaces</a>
	 */
	public String toClarkString()
	{
		return namespace == null ? name : "{" + namespace + "}" + name;
	}
} public class XmlContext
{
	final Map<QualifiedName, ElementDescriptor<?>> DESCRIPTOR_MAP = new HashMap<QualifiedName, ElementDescriptor<?>>(32);
} public abstract class AbstractObjectBuilder<T> implements IObjectBuilder<T>
{

	@Override
	public T get(ElementDescriptor<T> descriptor, T recycle, ParserContext context) throws XmlObjectPullParserException
	{
		return null;
	}


	@Override
	public T update(ElementDescriptor<T> descriptor, T object, QualifiedName attribute, String value, ParserContext context)
		throws XmlObjectPullParserException
	{
		return object;
	}


	@Override
	public T update(ElementDescriptor<T> descriptor, T object, String text, ParserContext context) throws XmlObjectPullParserException
	{
		return object;
	}


	@Override
	public <V> T update(ElementDescriptor<T> descriptor, T object, ElementDescriptor<V> childDescriptor, V child, ParserContext context)
		throws XmlObjectPullParserException
	{
		return object;
	}


	@Override
	public <V> T update(ElementDescriptor<T> descriptor, T object, QualifiedName anonymousChildName, IObjectBuilder<V> anonymousChildBuilder,
		V anonymousChild, ParserContext context) throws XmlObjectPullParserException
	{
		return object;
	}


	@Override
	public T finish(ElementDescriptor<T> descriptor, T object, ParserContext context) throws XmlObjectPullParserException
	{
		return object;
	}


	@Override
	public void writeAttributes(ElementDescriptor<T> descriptor, T object, IXmlAttributeWriter attributeWriter, SerializerContext context)
		throws SerializerException, IOException
	{
		// do nothing
	}


	@Override
	public void writeChildren(ElementDescriptor<T> descriptor, T object, IXmlChildWriter childWriter, SerializerContext context) throws SerializerException,
		IOException
	{
		// do nothing
	}
} public class ParserContext
{

	/**
	 * A cache of recycled objects. We cache one object per {@link ElementDescriptor}.
	 */
	private final Map<ElementDescriptor<?>, Object> mRecycledObjects = new HashMap<ElementDescriptor<?>, Object>(32);

	private List<Map<ElementDescriptor<?>, Object>> mState;

	/**
	 * The current {@link XmlPullParser} instance.
	 */
	private XmlPullParser mParser;

	private XmlObjectPull mObjectPullParser;


	/**
	 * Set the current {@link XmlObjectPull} parser this instance belongs to.
	 * 
	 * @param objectPullParser
	 */
	void setObjectPullParser(XmlObjectPull objectPullParser)
	{
		mObjectPullParser = objectPullParser;
	}


	/**
	 * Set the current {@link XmlPullParser} instance.
	 * 
	 * @param parser
	 *            The current {@link XmlPullParser}.
	 */
	void setXmlPullParser(XmlPullParser parser)
	{
		mParser = parser;
	}


	/**
	 * Returns the current {@link XmlPullParser} instance. You MUST NOT change the state of the parser, so don't call {@link XmlPullParser#next()},
	 * {@link XmlPullParser#nextTag()}, {@link XmlPullParser#nextText()} or {@link XmlPullParser#nextToken()}.
	 * 
	 * @return The current {@link XmlPullParser} instance.
	 */
	public XmlPullParser getXmlPullParser()
	{
		return mParser;
	}


	/**
	 * Recycle the given object. The basic implementation will store only one recycled object instance per {@link ElementDescriptor} in the recycler.
	 * 
	 * @param descriptor
	 *            The {@link ElementDescriptor} of the XML element
	 * @param object
	 *            The object to recycle.
	 */
	public <T> void recycle(ElementDescriptor<T> descriptor, T object)
	{
		if (object != null)
		{
			mRecycledObjects.put(descriptor, object);
		}
	}


	/**
	 * Get a recycled instance. If there was no instance in the recycler this method returns <code>null</code>.
	 * <p>
	 * <stong>Note:</strong> The object is returned exactly as passed to {@link #recycle(ElementDescriptor, Object)}, so you need to ensure you reset the state
	 * yourself.
	 * </p>
	 * 
	 * @param descriptor
	 *            The {@link ElementDescriptor} for which to return a recycled object.
	 * @return a recycled object or <code>null</code> if there is none.
	 */
	@SuppressWarnings("unchecked")
	public <T> T getRecycled(ElementDescriptor<T> descriptor)
	{
		// we can safely cast here, because we know that recycle always puts the right type
		return (T) mRecycledObjects.remove(descriptor);
	}


	/**
	 * Stores a state object for the current element and depth. Only elements with the same {@link ElementDescriptor} at the same depth can retrieve this state
	 * object through {@link #getState()}.
	 * <p>
	 * Builders should recycle the state object whenever possible.
	 * </p>
	 * 
	 * @param object
	 *            The state object to store or <code>null</code> to free this object.
	 */
	public void setState(Object object)
	{
		Map<ElementDescriptor<?>, Object> depthStateMap = getDepthStateMap(mObjectPullParser.getCurrentDepth(), true);

		ElementDescriptor<?> currentDescriptor = mObjectPullParser.getCurrentElementDescriptor();
		depthStateMap.put(currentDescriptor, object);
	}


	/**
	 * Get the state object of the current element. The object must have been set by {@link #setState(Object)}.
	 * 
	 * @return An {@link Object} or <code>null</code> if there is no state object.
	 */
	public Object getState()
	{
		Map<ElementDescriptor<?>, Object> stateMap = getDepthStateMap(mObjectPullParser.getCurrentDepth(), false);
		if (stateMap == null)
		{
			return null;
		}

		ElementDescriptor<?> currentDescriptor = mObjectPullParser.getCurrentElementDescriptor();
		return stateMap.get(currentDescriptor);
	}


	/**
	 * Return the element state map for the given depth, creating non-existing maps if required.
	 * 
	 * @param depth
	 *            The depth for which to retrieve the state map.
	 * @param create
	 *            <code>true</code> to create a new map if it doesn't exist.
	 * @return
	 */
	private Map<ElementDescriptor<?>, Object> getDepthStateMap(int depth, boolean create)
	{
		if (mState == null)
		{
			mState = new ArrayList<Map<ElementDescriptor<?>, Object>>(Math.max(16, depth + 8));
		}

		// fill array list with null values up to the current depth
		while (depth > mState.size())
		{
			mState.add(null);
		}

		Map<ElementDescriptor<?>, Object> map = mState.get(depth - 1 /* depth is at least 1 */);

		if (!create || map != null)
		{
			return map;
		}

		// map is null and we shall create it
		map = new HashMap<ElementDescriptor<?>, Object>(8);
		mState.set(depth - 1, map);
		return map;
	}

} public interface Recyclable
{
	/**
	 * Recycle this object.
	 */
	public void recycle();
} public class XmlObjectPullParserException extends Exception
{

	/**
	 * Generated serial ID.
	 */
	private static final long serialVersionUID = 7963991276367967034L;


	public XmlObjectPullParserException()
	{
		super();
	}


	public XmlObjectPullParserException(String message)
	{
		super(message);
	}


	public XmlObjectPullParserException(String message, Throwable cause)
	{
		super(message, cause);
	}

} public class SerializerContext
{
	/**
	 * The {@link XmlContext}.
	 */
	XmlContext xmlContext;

	/**
	 * The actual serializer.
	 */
	XmlSerializer serializer;

	/**
	 * A set of known name spaces.
	 */
	Set<String> knownNamespaces;


	public SerializerContext(XmlContext xmlContext) throws SerializerException
	{
		this.xmlContext = xmlContext;
		try
		{
			this.serializer = XmlPullParserFactory.newInstance().newSerializer();
		}
		catch (XmlPullParserException e)
		{
			throw new SerializerException("can't get serializer", e);
		}
	}


	/**
	 * Returns the current {@link XmlContext}.
	 * 
	 * @return The {@link XmlContext}, never <code>null</code>.
	 */
	public XmlContext getXmlContext()
	{
		return xmlContext;
	}
} public class SerializerException extends Exception
{
	/**
	 * Generated serial ID.
	 */
	private static final long serialVersionUID = -3185565961108391727L;


	public SerializerException(String message)
	{
		super(message);
	}


	public SerializerException(String message, Throwable cause)
	{
		super(message, cause);
	}
} public interface IXmlAttributeWriter
{
	/**
	 * Adds the given attribute to the current element.
	 * 
	 * @param name
	 *            The name of the attribute.
	 * @param value
	 *            The value of the attribute.
	 * @param serializerContext
	 *            The current {@link SerializerContext}.
	 * @throws SerializerException
	 * @throws IOException
	 */
	public void writeAttribute(QualifiedName name, String value, SerializerContext serializerContext) throws SerializerException, IOException;
} public interface IXmlChildWriter
{
	/**
	 * Add the given child element to the current element.
	 * 
	 * @param descriptor
	 *            The descriptor of the child to add.
	 * @param child
	 *            The child object.
	 * @param serializerContext
	 *            The current {@link SerializerContext}.
	 * @throws SerializerException
	 * @throws IOException
	 */
	public <T> void writeChild(ElementDescriptor<T> descriptor, T child, SerializerContext serializerContext) throws SerializerException, IOException;


	/**
	 * Add a text node to the current element.
	 * 
	 * @param text
	 *            The text to write.
	 * @param serializerContext
	 *            The current {@link SerializerContext}.
	 * @throws SerializerException
	 * @throws IOException
	 */
	public void writeText(String text, SerializerContext serializerContext) throws SerializerException, IOException;
}
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.dmfs.xmlobjects.ElementDescriptor;
import org.dmfs.xmlobjects.QualifiedName;
import org.dmfs.xmlobjects.XmlContext;
import org.dmfs.xmlobjects.builder.AbstractObjectBuilder;
import org.dmfs.xmlobjects.pull.ParserContext;
import org.dmfs.xmlobjects.pull.Recyclable;
import org.dmfs.xmlobjects.pull.XmlObjectPullParserException;
import org.dmfs.xmlobjects.serializer.SerializerContext;
import org.dmfs.xmlobjects.serializer.SerializerException;
import org.dmfs.xmlobjects.serializer.XmlObjectSerializer.IXmlAttributeWriter;
import org.dmfs.xmlobjects.serializer.XmlObjectSerializer.IXmlChildWriter;
			catch (IllegalArgumentException e)
			{
				throw new XmlObjectPullParserException("can not assign '" + data + "' to a field of type " + fieldType, e);
			}
			catch (IllegalAccessException e)
			{
				throw new XmlObjectPullParserException("can not assign '" + data + "' to a field of type " + fieldType, e);
			}
			catch (InstantiationException e)
			{
				throw new XmlObjectPullParserException("can not insanciate collection for " + fieldType, e);
			}
		}
		return object;
	}


	public T getInstance(ParserContext context) throws InstantiationException, IllegalAccessException
	{
		return mGenericClass.newInstance();
	}


	private void assignValue(Field field, Object object, String value) throws XmlObjectPullParserException
	{
		Class<?> fieldType = field.getType();
		try
		{
			if (fieldType == String.class)
			{
				field.set(object, value);
			}
			else if (fieldType == int.class || fieldType == Integer.class)
			{
				field.setInt(object, Integer.parseInt(value));
			}
			else if (fieldType == byte.class || fieldType == Byte.class)
			{
				field.setByte(object, Byte.parseByte(value));
			}
			else if (fieldType == char.class || fieldType == Character.class)
			{
				field.setChar(object, value.length() > 0 ? value.charAt(0) : null /* will throw if value is '' and field type is char */);
			}
			else if (fieldType == short.class || fieldType == Short.class)
			{
				field.setShort(object, Short.parseShort(value));
			}
			else if (fieldType == long.class || fieldType == Long.class)
			{
				field.setLong(object, Long.parseLong(value));
			}
			else if (fieldType == float.class || fieldType == Float.class)
			{
				field.setFloat(object, Float.parseFloat(value));
			}
			else if (fieldType == double.class || fieldType == Double.class)
			{
				field.setDouble(object, Double.parseDouble(value));
			}
			else if (fieldType == boolean.class || fieldType == Boolean.class)
			{
				field.setBoolean(object, Boolean.parseBoolean(value));
			}
			else if (fieldType == URI.class)
			{
				field.set(object, new URI(value));
			}
			else if (field.getType() == Class.class)
			{
				if (value != null)
				{
					try
					{
						field.set(object, Class.forName(value));
					}
					catch (ClassNotFoundException e)
					{
						// ignore
					}
				}
			}
			else if (Enum.class.isAssignableFrom(fieldType))
			{
				try
				{
					Method valueOf = fieldType.getMethod("valueOf", String.class);
					field.set(object, valueOf.invoke(fieldType, value));
				}
				catch (NoSuchMethodException e)
				{
					// this should not happen, we've checked that fieldType is an enum
				}
				catch (InvocationTargetException e)
				{
					// this should not happen, we've checked that fieldType is an enum
				}
			}
		}
		catch (NumberFormatException e)
		{
			throw new XmlObjectPullParserException("can not assign '" + value + "' to a field of type " + fieldType, e);
		}
		catch (IllegalArgumentException e)
		{
			throw new XmlObjectPullParserException("can not assign '" + value + "' to a field of type " + fieldType, e);
		}
		catch (IllegalAccessException e)
		{
			throw new XmlObjectPullParserException("can not assign '" + value + "' to a field of type " + fieldType, e);
		}
		catch (URISyntaxException e)
		{
			throw new XmlObjectPullParserException("can not parse URI in '" + value + "'", e);
		}
	}


	@Override
	public void writeAttributes(ElementDescriptor<T> descriptor, T object, IXmlAttributeWriter attributeWriter, SerializerContext context)
		throws SerializerException, IOException