org.simpleframework.xml.core.GroupExtractor 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!
/*
* GroupExtractor.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.lang.annotation.Annotation;
import java.util.Iterator;
import java.util.LinkedHashMap;
import org.simpleframework.xml.Text;
import org.simpleframework.xml.stream.Format;
/**
* The GroupExtractor
represents an extractor for labels
* associated with a particular union annotation. This extractor
* registers Label
by name and by type. Acquiring
* the label by type allows the serialization process to dynamically
* select a label, and thus converter, based on the instance type.
* On deserialization a label is dynamically selected based on name.
*
* @author Niall Gallagher
*
* @see org.simpleframework.xml.core.Group
*/
class GroupExtractor implements Group {
/**
* This represents a factory for creating union extractors.
*/
private final ExtractorFactory factory;
/**
* This represents the union label to be used for this group.
*/
private final Annotation label;
/**
* This contains each label registered by name and by type.
*/
private final Registry registry;
/**
* This contains each label registered by label name.
*/
private final LabelMap elements;
/**
* Constructor for the GroupExtractor
object. This
* will create an extractor for the provided union annotation.
* Each individual declaration within the union is extracted
* and made available within the group.
*
* @param contact this is the annotated field or method
* @param label this is the label associated with the contact
* @param format this is the format used by this extractor
*/
public GroupExtractor(Contact contact, Annotation label, Format format) throws Exception{
this.factory = new ExtractorFactory(contact, label, format);
this.elements = new LabelMap();
this.registry = new Registry(elements);
this.label = label;
this.extract();
}
/**
* This is used to acquire the names for each label associated
* with this Group
instance. The names provided
* here are not styled according to a serialization context.
*
* @return this returns the names of each union extracted
*/
public String[] getNames() throws Exception {
return elements.getKeys();
}
/**
* This is used to acquire the paths for each label associated
* with this Group
instance. The paths provided
* here are not styled according to a serialization context.
*
* @return this returns the paths of each union extracted
*/
public String[] getPaths() throws Exception {
return elements.getPaths();
}
/**
* This is used to acquire a LabelMap
containing the
* labels available to the group. Providing a context object
* ensures that each of the labels is mapped to a name that is
* styled according to its internal style.
*
* @return this returns a label map containing the labels
*/
public LabelMap getElements() throws Exception {
return elements.getLabels();
}
/**
* This is used to acquire a Label
based on the type
* of an object. Selecting a label based on the type ensures that
* the serialization process can dynamically convert an object
* to XML. If the type is not supported, this returns null.
*
* @param type this is the type to select the label from
*
* @return this returns the label based on the type
*/
public Label getLabel(Class type) {
return registry.resolve(type);
}
/**
* This is used to get a Label
that represents the
* text between elements on an element union. Providing a label
* here ensures that the free text found between elements can
* be converted in to strings and added to the list.
*
* @return a label if a text annotation has been declared
*/
public Label getText() {
return registry.resolveText();
}
/**
* This is used to determine if the associated type represents a
* label defined within the union group. If the label exists
* this returns true, if not then this returns false.
*
* @param type this is the type to check for
*
* @return this returns true if a label for the type exists
*/
public boolean isValid(Class type) {
return registry.resolve(type) != null;
}
/**
* This is used to determine if a type has been declared by the
* annotation associated with the group. Unlike determining if
* the type is valid this will not consider super types.
*
* @param type this is the type to determine if it is declared
*
* @return this returns true if the type has been declared
*/
public boolean isDeclared(Class type) {
return registry.containsKey(type);
}
/**
* This is used to determine if the group is inline. A group is
* inline if all of the elements in the group is inline. If any of
* the Label objects in the group is not inline then
* the entire group is not inline, although this is unlikely.
*
* @return this returns true if each label in the group is inline
*/
public boolean isInline() {
for(Label label : registry) {
if(!label.isInline()) {
return false;
}
}
return !registry.isEmpty();
}
/**
* This is used to determine if an annotated list is a text
* list. A text list is a list of elements that also accepts
* free text. Typically this will be an element list union that
* will allow unstructured XML such as XHTML to be parsed.
*
* @return returns true if the label represents a text list
*/
public boolean isTextList() {
return registry.isText();
}
/**
* This is used to extract the labels associated with the group.
* Extraction will instantiate a Label
object for
* an individual annotation declared within the union. Each of
* the label instances is then registered by both name and type.
*/
private void extract() throws Exception {
Extractor extractor = factory.getInstance();
if(extractor != null) {
extract(extractor);
}
}
/**
* This is used to extract the labels associated with the group.
* Extraction will instantiate a Label
object for
* an individual annotation declared within the union. Each of
* the label instances is then registered by both name and type.
*
* @param extractor this is the extractor to get labels for
*/
private void extract(Extractor extractor) throws Exception {
Annotation[] list = extractor.getAnnotations();
for(Annotation label : list) {
extract(extractor, label);
}
}
/**
* This is used to extract the labels associated with the group.
* Extraction will instantiate a Label
object for
* an individual annotation declared within the union. Each of
* the label instances is then registered by both name and type.
*
* @param extractor this is the extractor to get labels for
* @param value this is an individual annotation declared
*/
private void extract(Extractor extractor, Annotation value) throws Exception {
Label label = extractor.getLabel(value);
Class type = extractor.getType(value);
if(registry != null) {
registry.register(type, label);
}
}
/**
* This returns a string representation of the union group.
* Providing a string representation in this way ensures that the
* group can be used in exception messages and for any debugging.
*
* @return this returns a string representation of the group
*/
public String toString() {
return label.toString();
}
/**
* The Registry
object is used to maintain mappings
* from types to labels. Each of the mappings can be used to
* dynamically select a label based on the instance type that is
* to be serialized. This also registers based on the label name.
*/
private static class Registry extends LinkedHashMap implements Iterable