org.simpleframework.xml.core.Entry 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!
/*
* Entry.java July 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.core;
import org.simpleframework.xml.ElementMap;
import org.simpleframework.xml.strategy.Type;
/**
* The Entry
object is used to provide configuration for
* the serialization and deserialization of a map. Values taken from
* the ElementMap
annotation provide a means to specify
* how to read and write the map as an XML element. Key and value
* objects can be written as composite or primitive values. Primitive
* key values can be written as attributes of the resulting entry
* and value objects can be written inline if desired.
*
* @author Niall Gallagher
*/
class Entry {
/**
* Provides the default name for entry XML elements of the map.
*/
private static final String DEFAULT_NAME = "entry";
/**
* Represents the annotation that the map object is labeled with.
*/
private ElementMap label;
/**
* Provides the point of contact in the object to the map.
*/
private Contact contact;
/**
* Provides the class XML schema used for the value objects.
*/
private Class valueType;
/**
* Provides the class XML schema used for the key objects.
*/
private Class keyType;
/**
* Specifies the name of the XML entry element used by the map.
*/
private String entry;
/**
* Specifies the name of the XML value element used by the map.
*/
private String value;
/**
* Specifies the name of the XML key node used by the map.
*/
private String key;
/**
* Determines whether the key object is written as an attribute.
*/
private boolean attribute;
/**
* Constructor for the Entry
object. This takes the
* element map annotation that provides configuration as to how
* the map is serialized and deserialized from the XML document.
* The entry object provides a convenient means to access the XML
* schema configuration using defaults where necessary.
*
* @param contact this is the point of contact to the map object
* @param label the annotation the map method or field uses
*/
public Entry(Contact contact, ElementMap label) {
this.attribute = label.attribute();
this.entry = label.entry();
this.value = label.value();
this.key = label.key();
this.contact = contact;
this.label = label;
}
/**
* This represents the field or method that has been annotated as
* a map. This can be used to acquire information on the field or
* method. Also, as a means of reporting errors this can be used.
*
* @return this returns the contact associated with the map
*/
public Contact getContact() {
return contact;
}
/**
* Represents whether the key value is to be an attribute or an
* element. This allows the key to be embedded within the entry
* XML element allowing for a more compact representation. Only
* primitive key objects can be represented as an attribute. For
* example a java.util.Date
or a string could be
* represented as an attribute key for the generated XML.
*
* @return true if the key is to be inlined as an attribute
*/
public boolean isAttribute() {
return attribute;
}
/**
* Represents whether the value is to be written as an inline text
* value within the element. This is only possible if the key has
* been specified as an attribute. Also, the value can only be
* inline if there is no wrapping value XML element specified.
*
* @return this returns true if the value can be written inline
*/
public boolean isInline() throws Exception {
return isAttribute();
}
/**
* This is used to get the key converter for the entry. This knows
* whether the key type is a primitive or composite object and will
* provide the appropriate converter implementation. This allows
* the root composite map converter to concern itself with only the
* details of the surrounding entry object.
*
* @param context this is the root context for the serialization
*
* @return returns the converter used for serializing the key
*/
public Converter getKey(Context context) throws Exception {
Type type = getKeyType();
if(context.isPrimitive(type)) {
return new PrimitiveKey(context, this, type);
}
return new CompositeKey(context, this, type);
}
/**
* This is used to get the value converter for the entry. This knows
* whether the value type is a primitive or composite object and will
* provide the appropriate converter implementation. This allows
* the root composite map converter to concern itself with only the
* details of the surrounding entry object.
*
* @param context this is the root context for the serialization
*
* @return returns the converter used for serializing the value
*/
public Converter getValue(Context context) throws Exception {
Type type = getValueType();
if(context.isPrimitive(type)) {
return new PrimitiveValue(context, this, type);
}
return new CompositeValue(context, this, type);
}
/**
* This is used to acquire the dependent key for the annotated
* map. This will simply return the type that the map object is
* composed to hold. This must be a serializable type, that is,
* it must be a composite or supported primitive type.
*
* @return this returns the key object type for the map object
*/
protected Type getKeyType() throws Exception {
if(keyType == null) {
keyType = label.keyType();
if(keyType == void.class) {
keyType = getDependent(0);
}
}
return new ClassType(keyType);
}
/**
* This is used to acquire the dependent value for the annotated
* map. This will simply return the type that the map object is
* composed to hold. This must be a serializable type, that is,
* it must be a composite or supported primitive type.
*
* @return this returns the value object type for the map object
*/
protected Type getValueType() throws Exception {
if(valueType == null) {
valueType = label.valueType();
if(valueType == void.class) {
valueType = getDependent(1);
}
}
return new ClassType(valueType);
}
/**
* Provides the dependent class for the map as taken from the
* specified index. This allows the entry to fall back on generic
* declarations of the map if no explicit dependent types are
* given within the element map annotation.
*
* @param index this is the index to acquire the parameter from
*
* @return this returns the generic type at the specified index
*/
private Class getDependent(int index) throws Exception {
Class[] list = contact.getDependents();
if(list.length < index) {
return Object.class;
}
if(list.length == 0) {
return Object.class;
}
return list[index];
}
/**
* This is used to provide a key XML element for each of the
* keys within the map. This essentially wraps the entity to
* be serialized such that there is an extra XML element present.
* This can be used to override the default names of primitive
* keys, however it can also be used to wrap composite keys.
*
* @return this returns the key XML element for each key
*/
public String getKey() throws Exception {
if(key == null) {
return key;
}
if(isEmpty(key)) {
key = null;
}
return key;
}
/**
* This is used to provide a value XML element for each of the
* values within the map. This essentially wraps the entity to
* be serialized such that there is an extra XML element present.
* This can be used to override the default names of primitive
* values, however it can also be used to wrap composite values.
*
* @return this returns the value XML element for each value
*/
public String getValue() throws Exception {
if(value == null) {
return value;
}
if(isEmpty(value)) {
value = null;
}
return value;
}
/**
* This is used to provide a the name of the entry XML element
* that wraps the key and value elements. If specified the entry
* value specified will be used instead of the default name of
* the element. This is used to ensure the resulting XML is
* configurable to the requirements of the generated XML.
*
* @return this returns the entry XML element for each entry
*/
public String getEntry() throws Exception {
if(entry == null) {
return entry;
}
if(isEmpty(entry)) {
entry = DEFAULT_NAME;
}
return entry;
}
/**
* This method is used to determine if a root annotation value is
* an empty value. Rather than determining if a string is empty
* be comparing it to an empty string this method allows for the
* value an empty string represents to be changed in future.
*
* @param value this is the value to determine if it is empty
*
* @return true if the string value specified is an empty value
*/
private boolean isEmpty(String value) {
return value.length() == 0;
}
/**
* This provides a textual representation of the annotated field
* or method for the map. Providing a textual representation allows
* exception messages to be reported with sufficient information.
*
* @return this returns the textual representation of the label
*/
public String toString() {
return String.format("%s on %s", label, contact);
}
}