org.simpleframework.xml.strategy.ReadGraph 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
/*
* ReadGraph.java April 2007
*
* Copyright (C) 2007, 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.strategy;
import org.simpleframework.xml.stream.NodeMap;
import org.simpleframework.xml.stream.Node;
import java.util.HashMap;
/**
* The ReadGraph
object is used to build a graph of the
* objects that have been deserialized from the XML document. This is
* required so that cycles in the object graph can be recreated such
* that the deserialized object is an exact duplicate of the object
* that was serialized. Objects are stored in the graph using unique
* keys, which for this implementation are unique strings.
*
* @author Niall Gallagher
*
* @see org.simpleframework.xml.strategy.WriteGraph
*/
class ReadGraph extends HashMap {
/**
* This is the class loader that is used to load the types used.
*/
private final Loader loader;
/**
* This is used to represent the length of array object values.
*/
private final String length;
/**
* This is the label used to mark the type of an object.
*/
private final String label;
/**
* This is the attribute used to mark the identity of an object.
*/
private final String mark;
/**
* This is the attribute used to refer to an existing instance.
*/
private final String refer;
/**
* Constructor for the ReadGraph
object. This is used
* to create graphs that are used for reading objects from the XML
* document. The specified strategy is used to acquire the names
* of the special attributes used during the serialization.
*
* @param contract this is the name scheme used by the strategy
* @param loader this is the class loader to used for the graph
*/
public ReadGraph(Contract contract, Loader loader) {
this.refer = contract.getReference();
this.mark = contract.getIdentity();
this.length = contract.getLength();
this.label = contract.getLabel();
this.loader = loader;
}
/**
* This is used to recover the object references from the document
* using the special attributes specified. This allows the element
* specified by the NodeMap
to be used to discover
* exactly which node in the object graph the element represents.
*
* @param type the type of the field or method in the instance
* @param node this is the XML element to be deserialized
*
* @return this is used to return the type to acquire the value
*/
public Value read(Type type, NodeMap node) throws Exception {
Node entry = node.remove(label);
Class expect = type.getType();
if(expect.isArray()) {
expect = expect.getComponentType();
}
if(entry != null) {
String name = entry.getValue();
expect = loader.load(name);
}
return readInstance(type, expect, node);
}
/**
* This is used to recover the object references from the document
* using the special attributes specified. This allows the element
* specified by the NodeMap
to be used to discover
* exactly which node in the object graph the element represents.
*
* @param type the type of the field or method in the instance
* @param real this is the overridden type from the XML element
* @param node this is the XML element to be deserialized
*
* @return this is used to return the type to acquire the value
*/
private Value readInstance(Type type, Class real, NodeMap node) throws Exception {
Node entry = node.remove(mark);
if(entry == null) {
return readReference(type, real, node);
}
String key = entry.getValue();
if(containsKey(key)) {
throw new CycleException("Element '%s' already exists", key);
}
return readValue(type, real, node, key);
}
/**
* This is used to recover the object references from the document
* using the special attributes specified. This allows the element
* specified by the NodeMap
to be used to discover
* exactly which node in the object graph the element represents.
*
* @param type the type of the field or method in the instance
* @param real this is the overridden type from the XML element
* @param node this is the XML element to be deserialized
*
* @return this is used to return the type to acquire the value
*/
private Value readReference(Type type, Class real, NodeMap node) throws Exception {
Node entry = node.remove(refer);
if(entry == null) {
return readValue(type, real, node);
}
String key = entry.getValue();
Object value = get(key);
if(!containsKey(key)) {
throw new CycleException("Invalid reference '%s' found", key);
}
return new Reference(value, real);
}
/**
* This is used to acquire the Value
which can be used
* to represent the deserialized value. The type create cab be
* added to the graph of created instances if the XML element has
* an identification attribute, this allows cycles to be completed.
*
* @param type the type of the field or method in the instance
* @param real this is the overridden type from the XML element
* @param node this is the XML element to be deserialized
*
* @return this is used to return the type to acquire the value
*/
private Value readValue(Type type, Class real, NodeMap node) throws Exception {
Class expect = type.getType();
if(expect.isArray()) {
return readArray(type, real, node);
}
return new ObjectValue(real);
}
/**
* This is used to acquire the Value
which can be used
* to represent the deserialized value. The type create cab be
* added to the graph of created instances if the XML element has
* an identification attribute, this allows cycles to be completed.
*
* @param type the type of the field or method in the instance
* @param real this is the overridden type from the XML element
* @param node this is the XML element to be deserialized
* @param key the key the instance is known as in the graph
*
* @return this is used to return the type to acquire the value
*/
private Value readValue(Type type, Class real, NodeMap node, String key) throws Exception {
Value value = readValue(type, real, node);
if(key != null) {
return new Allocate(value, this, key);
}
return value;
}
/**
* This is used to acquire the Value
which can be used
* to represent the deserialized value. The type create cab be
* added to the graph of created instances if the XML element has
* an identification attribute, this allows cycles to be completed.
*
* @param type the type of the field or method in the instance
* @param real this is the overridden type from the XML element
* @param node this is the XML element to be deserialized
*
* @return this is used to return the type to acquire the value
*/
private Value readArray(Type type, Class real, NodeMap node) throws Exception {
Node entry = node.remove(length);
int size = 0;
if(entry != null) {
String value = entry.getValue();
size = Integer.parseInt(value);
}
return new ArrayValue(real, size);
}
}