org.simpleframework.xml.core.CompositeListUnion 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!
/*
* CompositeListUnion.java March 2011
*
* Copyright (C) 2011, 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 java.util.Collection;
import java.util.Collections;
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 CompositeListUnion
object is used to act as a
* mediator for multiple converters associated with a particular union
* group. This will basically determine which Converter
* should be delegated to based on either the XML element name being read
* or the type of the instance object being written. Selection of the
* converter is done by consulting the Group
of labels
* representing the union declaration.
*
* @author Niall Gallagher
*/
class CompositeListUnion implements Repeater {
/**
* This contains the labels in the union group keyed by name.
*/
private final LabelMap elements;
/**
* This is the path expression used to represent this union.
*/
private final Expression path;
/**
* This is the current context used for the serialization.
*/
private final Context context;
/**
* This contains the group of labels associated with the union.
*/
private final Group group;
/**
* This is this style associated with the serialization context.
*/
private final Style style;
/**
* This is the type field or method annotated as a union.
*/
private final Type type;
/**
* Constructor for the CompositeListUnion
object. This
* is used to create a converter that delegates to other associated
* converters within the union group depending on the XML element
* name being read or the instance type that is being written.
*
* @param context this is the context used for the serialization
* @param group this is the union group used for delegation
* @param path this is the path expression representing this union
* @param type this is the annotated field or method to be used
*/
public CompositeListUnion(Context context, Group group, Expression path, Type type) throws Exception {
this.elements = group.getElements();
this.style = context.getStyle();
this.context = context;
this.group = group;
this.type = type;
this.path = path;
}
/**
* The read
method uses the name of the XML element to
* select a converter to be used to read the instance. Selection of
* the converter is done by looking up the associated label from
* the union group using the element name. Once the converter has
* been selected it is used to read the instance.
*
* @param node this is the XML element used to read the instance
*
* @return this is the instance that has been read by this
*/
public Object read(InputNode node) throws Exception {
Label text = group.getText();
if(text == null) {
return readElement(node);
}
return readText(node);
}
/**
* The readElement
method uses the name of the element
* to select a converter to be used to read the instance. Selection
* of the converter is done by looking up the associated label from
* the union group using the element name. Once the converter has
* been selected it is used to read the instance.
*
* @param node this is the XML element used to read the instance
*
* @return this is the instance that has been read by this
*/
private Object readElement(InputNode node) throws Exception {
String name = node.getName();
String element = path.getElement(name);
Label label = elements.get(element);
Converter converter = label.getConverter(context);
return converter.read(node);
}
/**
* The readText
method is used to read free text from
* between the declared elements and add them to a list. Consuming
* free text in this manner enables an element list union to parse
* unstructured XML such as XHTML.
*
* @param node this is the node to consume the free text from
*
* @return this returns the list with the text added to it
*/
private Object readText(InputNode node) throws Exception {
Label text = group.getText();
Converter converter = text.getConverter(context);
return converter.read(node);
}
/**
* The read
method uses the name of the XML element to
* select a converter to be used to read the instance. Selection
* of the converter is done by looking up the associated label from
* the union group using the element name. Once the converter has
* been selected it is used to read the instance.
*
* @param node this is the XML element used to read the instance
* @param value this is the value that is to be repeated
*
* @return this is the instance that has been read by this
*/
public Object read(InputNode node, Object value) throws Exception {
Object result = readElement(node, value);
Label text = group.getText();
if(text != null) {
return readText(node, value);
}
return result;
}
/**
* The readElement
method uses the name of the element
* to select a converter to be used to read the instance. Selection
* of the converter is done by looking up the associated label from
* the union group using the element name. Once the converter has
* been selected it is used to read the instance.
*
* @param node this is the XML element used to read the instance
* @param value this is the value that is to be repeated
*
* @return this is the instance that has been read by this
*/
private Object readElement(InputNode node, Object value) throws Exception {
String name = node.getName();
String element = path.getElement(name);
Label label = elements.get(element);
Converter converter = label.getConverter(context);
return converter.read(node, value);
}
/**
* The readText
method is used to read free text from
* between the declared elements and add them to a list. Consuming
* free text in this manner enables an element list union to parse
* unstructured XML such as XHTML.
*
* @param node this is the node to consume the free text from
* @param value this is the value that is to be repeated
*
* @return this returns the list with the text added to it
*/
private Object readText(InputNode node, Object value) throws Exception {
Label label = group.getText();
Converter converter = label.getConverter(context);
InputNode parent = node.getParent();
return converter.read(parent, value);
}
/**
* The validate
method is used to validate the XML
* element provided using an associated class schema. The schema
* is selected using the name of the XML element to acquire
* the associated converter. Once the converter has been acquired
* it is delegated to and validated against it.
*
* @param node this is the input XML element to be validated
*
* @return this returns true if the node validates
*/
public boolean validate(InputNode node) throws Exception {
String name = node.getName();
String element = path.getElement(name);
Label label = elements.get(element);
Converter converter = label.getConverter(context);
return converter.validate(node);
}
/**
* The write
method uses the name of the XML element to
* select a converter to be used to write the instance. Selection of
* the converter is done by looking up the associated label from
* the union group using the instance type. Once the converter has
* been selected it is used to write the instance.
*
* @param source this is the source collection to be serialized
* @param node this is the XML element container to be populated
*/
public void write(OutputNode node, Object source) throws Exception {
Collection list = (Collection) source;
if(group.isInline()) {
if(!list.isEmpty()) {
write(node, list);
} else if(!node.isCommitted()){
node.remove();
}
} else {
write(node, list);
}
}
/**
* The write
method uses the name of the XML element to
* select a converter to be used to write the instance. Selection of
* the converter is done by looking up the associated label from
* the union group using the instance type. Once the converter has
* been selected it is used to write the instance.
*
* @param node this is the XML element used to write the instance
* @param list this is the value that is to be written
*/
private void write(OutputNode node, Collection list) throws Exception {
for(Object item : list) {
if(item != null) {
Class real = item.getClass();
Label label = group.getLabel(real);
if(label == null) {
throw new UnionException("Entry of %s not declared in %s with annotation %s", real, type, group);
}
write(node, item, label);
}
}
}
/**
* The write
method uses the name of the XML element to
* select a converter to be used to write the instance. Selection of
* the converter is done by looking up the associated label from
* the union group using the instance type. Once the converter has
* been selected it is used to write the instance.
*
* @param node this is the XML element used to write the instance
* @param item this is the individual list entry to be serialized
* @param label this is the label to used to acquire the converter
*/
private void write(OutputNode node, Object item, Label label) throws Exception {
Converter converter = label.getConverter(context);
Collection list = Collections.singleton(item);
if(!label.isInline()) {
String name = label.getName();
String root = style.getElement(name);
if(!node.isCommitted()) {
node.setName(root);
}
}
converter.write(node, list);
}
}