org.simpleframework.xml.core.Traverser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of simple-xml Show documentation
Show all versions of simple-xml Show documentation
Simple is a high performance XML serialization and configuration framework for Java
The newest version!
/*
* Traverser.java July 2006
*
* Copyright (C) 2006, Niall Gallagher
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.simpleframework.xml.core;
import org.simpleframework.xml.strategy.Type;
import org.simpleframework.xml.stream.InputNode;
import org.simpleframework.xml.stream.OutputNode;
import org.simpleframework.xml.stream.Style;
/**
* The Traverser
object is used to traverse the XML class
* schema and either serialize or deserialize an object. This is the
* root of all serialization and deserialization operations. It uses
* the Root
annotation to ensure that the XML schema
* matches the provided XML element. If no root element is defined the
* serialization and deserialization cannot be performed.
*
* @author Niall Gallagher
*/
class Traverser {
/**
* This is the context object used for the traversal performed.
*/
private final Context context;
/**
* This is the style that is used to style the XML roots.
*/
private final Style style;
/**
* Constructor for the Traverser
object. This creates
* a traverser that can be used to perform serialization or
* or deserialization of an object. This requires a source object.
*
* @param context the context object used for the traversal
*/
public Traverser(Context context) {
this.style = context.getStyle();
this.context = context;
}
/**
* This will acquire the Decorator
for the type.
* A decorator is an object that adds various details to the
* node without changing the overall structure of the node. For
* example comments and namespaces can be added to the node with
* a decorator as they do not affect the deserialization.
*
* @param type this is the type to acquire the decorator for
*
* @return this returns the decorator associated with this
*/
private Decorator getDecorator(Class type) throws Exception {
return context.getDecorator(type);
}
/**
* This read
method is used to deserialize an object
* from the provided XML element. The class provided acts as the
* XML schema definition used to control the deserialization. If
* the XML schema does not have a Root
annotation
* this throws an exception. Also if the root annotation name is
* not the same as the XML element name an exception is thrown.
*
* @param node this is the node that is to be deserialized
* @param type this is the XML schema class to be used
*
* @return an object deserialized from the XML element
*
* @throws Exception if the XML schema does not match the node
*/
public Object read(InputNode node, Class type) throws Exception {
Composite factory = getComposite(type);
Object value = factory.read(node);
if(value != null) {
Class real = value.getClass();
return read(node, real, value);
}
return null;
}
/**
* This read
method will read the contents of the XML
* document from the provided source and populate the object with
* the values deserialized. This is used as a means of injecting an
* object with values deserialized from an XML document. If the
* XML source cannot be deserialized or there is a problem building
* the object graph an exception is thrown.
*
* @param node this is the node that is to be deserialized
* @param value this is the value that is to be deserialized
*
* @return an object deserialized from the XML element
*
* @throws Exception if the XML schema does not match the node
*/
public Object read(InputNode node, Object value) throws Exception {
Class type = value.getClass();
Composite factory = getComposite(type);
Object real = factory.read(node, value);
return read(node, type, real);
}
/**
* This read
method is used to deserialize an object
* from the provided XML element. The class provided acts as the
* XML schema definition used to control the deserialization. If
* the XML schema does not have a Root
annotation
* this throws an exception. Also if the root annotation name is
* not the same as the XML element name an exception is thrown.
*
* @param node this is the node that is to be deserialized
* @param value this is the XML schema object to be used
*
* @return an object deserialized from the XML element
*
* @throws Exception if the XML schema does not match the XML
*/
private Object read(InputNode node, Class type, Object value) throws Exception {
String root = getName(type);
if(root == null) {
throw new RootException("Root annotation required for %s", type);
}
return value;
}
/**
* This validate
method will validate the contents of
* the XML document against the specified XML class schema. This is
* used to perform a read traversal of the class schema such that
* the document can be tested against it. This is preferred to
* reading the document as it does not instantiate the objects or
* invoke any callback methods, thus making it a safe validation.
*
* @param type this is the class type to be validated against XML
* @param node this provides the source of the XML document
*
* @return true if the document matches the class XML schema
*
* @throws Exception if the class XML schema does not fully match
*/
public boolean validate(InputNode node, Class type) throws Exception {
Composite factory = getComposite(type);
String root = getName(type);
if(root == null) {
throw new RootException("Root annotation required for %s", type);
}
return factory.validate(node);
}
/**
* This write
method is used to convert the provided
* object to an XML element. This creates a child node from the
* given OutputNode
object. Once this child element
* is created it is populated with the fields of the source object
* in accordance with the XML schema class.
*
* @param source this is the object to be serialized to XML
*
* @throws Exception thrown if there is a problem serializing
*/
public void write(OutputNode node, Object source) throws Exception {
write(node, source, source.getClass());
}
/**
* This write
method is used to convert the provided
* object to an XML element. This creates a child node from the
* given OutputNode
object. Once this child element
* is created it is populated with the fields of the source object
* in accordance with the XML schema class.
*
* @param source this is the object to be serialized to XML
* @param expect this is the class that is expected to be written
*
* @throws Exception thrown if there is a problem serializing
*/
public void write(OutputNode node, Object source, Class expect) throws Exception {
Class type = source.getClass();
String root = getName(type);
if(root == null) {
throw new RootException("Root annotation required for %s", type);
}
write(node, source, expect, root);
}
/**
* This write
method is used to convert the provided
* object to an XML element. This creates a child node from the
* given OutputNode
object. Once this child element
* is created it is populated with the fields of the source object
* in accordance with the XML schema class.
*
* @param source this is the object to be serialized to XML
* @param expect this is the class that is expected to be written
* @param name this is the name of the root annotation used
*
* @throws Exception thrown if there is a problem serializing
*/
public void write(OutputNode node, Object source, Class expect, String name) throws Exception {
OutputNode child = node.getChild(name);
Type type = getType(expect);
if(source != null) {
Class actual = source.getClass();
Decorator decorator = getDecorator(actual);
if(decorator != null) {
decorator.decorate(child);
}
if(!context.setOverride(type, source, child)) {
getComposite(actual).write(child, source);
}
}
child.commit();
}
/**
* This will create a Composite
object using the XML
* schema class provided. This makes use of the source object that
* this traverser has been given to create a composite converter.
*
* @param expect this is the XML schema class to be used
*
* @return a converter for the specified XML schema class
*/
private Composite getComposite(Class expect) throws Exception {
Type type = getType(expect);
if(expect == null) {
throw new RootException("Can not instantiate null class");
}
return new Composite(context, type);
}
/**
* This is used to acquire a type for the provided class. This will
* wrap the class in a Type
wrapper object. Wrapping
* the class allows it to be used within the framework.
*
* @param type this is the type that is to be wrapped for use
*
* @return this returns the type that wraps the specified class
*/
private Type getType(Class type) {
return new ClassType(type);
}
/**
* Extracts the Root
annotation from the provided XML
* schema class. If no annotation exists in the provided class the
* super class is checked and so on until the Object
* is encountered, if no annotation is found this returns null.
*
* @param type this is the XML schema class to use
*
* @return this returns the root annotation for the XML schema
*/
protected String getName(Class type) throws Exception {
String root = context.getName(type);
String name = style.getElement(root);
return name;
}
}