com.tangosol.run.xml.MapAdapter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of coherence Show documentation
Show all versions of coherence Show documentation
Oracle Coherence Community Edition
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
package com.tangosol.run.xml;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Iterator;
/**
* A MapAdapter supports properties whose types implement the java.util.Map
* interface.
*
* {@code
* <property>
* <name>People</name>
* <xml-name>people</xml-name> <!-- defaults to <name> -->
* <type>java.util.Map</type> <!-- defaults via reflection -->
* <class>java.util.HashMap</class> <!-- defaults to <type> -->
* <empty-is-null>true</empty-is-null> <!-- defaults to false -->
* <element>
* <xml-name>person</xml-name> <!-- required -->
* <key>
* <name>ssn</name> <!-- defaults to "key" -->
* <xml-name>ssn</xml-name> <!-- defaults to <name> -->
* <type>String</type> <!-- required -->
* <adapter>...</adapter> <!-- optional -->
* <...> <!-- for the type-specific adapter -->
* </key>
* <value>
* <name>info</name> <!-- defaults to "value" -->
* <xml-name>info</xml-name> <!-- defaults to <name> -->
* <type>com...PersonBean</type> <!-- required -->
* <adapter>...</adapter> <!-- optional -->
* <...> <!-- for the type-specific adapter -->
* </value>
* </elelemt>
* </property>
*
* Example of map nested within collection tags:
*
* <doc>
* <people>
* <person>
* <ssn>...</ssn>
* <info>...</info>
* </person>
* <person>
* <ssn>...</ssn>
* <info>...</info>
* </person>
* ...
* </people>
* </doc>
* }
*
* @version 1.00 2001.03.18
* @author cp
*/
public class MapAdapter
extends IterableAdapter
{
// ----- constructors ---------------------------------------------------
/**
* Construct a MapAdapter.
*
* @param infoBean BeanInfo for a bean containing this property
* @param clzType the type of the property
* @param sName the property name
* @param sXml the XML tag name
* @param xml additional XML information
*/
public MapAdapter(XmlBean.BeanInfo infoBean, Class clzType, String sName, String sXml, XmlElement xml)
{
super(infoBean, clzType, sName, sXml, xml);
azzert(Map.class.isAssignableFrom(clzType));
Class clzMap = getType();
XmlValue xmlClz = xml.getElement("class");
if (xmlClz != null)
{
clzMap = infoBean.resolveClass(xmlClz.getString());
}
m_clzMap = clzMap;
m_adapterKey = findAdapter(infoBean, xml.findElement("element/key"));
m_adapterValue = findAdapter(infoBean, xml.findElement("element/value"));
}
// ----- Object method helpers ------------------------------------------
/**
* Make a clone of the passed object.
*
* @param o the object to clone
*
* @return a clone of the passed object
*/
public Object clone(Object o)
{
if (o == null)
{
return null;
}
PropertyAdapter adapterKey = m_adapterKey;
PropertyAdapter adapterValue = m_adapterValue;
Map mapOld = (Map) o;
Map mapNew = instantiateMap();
for (Iterator iter = mapOld.entrySet().iterator(); iter.hasNext(); )
{
Map.Entry entry = (Map.Entry) iter.next();
Object oKey = entry.getKey();
if (oKey != null)
{
oKey = adapterKey.clone(oKey);
}
Object oValue = entry.getValue();
if (oValue != null)
{
oValue = adapterValue.clone(oValue);
}
mapNew.put(oKey, oValue);
}
return mapNew;
}
// ----- XmlSerializable helpers ----------------------------------------
/**
* @param xml the XML element containing the XML elements to deserialize
* from
*
* @return the object deserialized from the XML (not null)
*/
protected Object readElements(XmlElement xml)
{
String sElement = getElementName();
if (sElement == null)
{
sElement = "entry";
}
PropertyAdapter adapterKey = m_adapterKey;
PropertyAdapter adapterValue = m_adapterValue;
Map map = instantiateMap();
Iterator iter = XmlHelper.getElements(xml, sElement, getNamespaceUri());
while (iter.hasNext())
{
XmlElement xmlEntry = (XmlElement) iter.next();
XmlElement xmlKey = adapterKey.findElement(xmlEntry);
Object oKey = null;
if (xmlKey != null)
{
oKey = adapterKey.fromXml(xmlKey);
}
XmlElement xmlValue = adapterValue.findElement(xmlEntry);
Object oValue = null;
if (xmlValue != null)
{
oValue = adapterValue.fromXml(xmlValue);
}
map.put(oKey, oValue);
}
return map;
}
/**
* @param xml the XML element to which the iterable elements are written
* @param o the object to serialize (not null)
*/
protected void writeElements(XmlElement xml, Object o)
{
String sElement = XmlHelper.getUniversalName(getElementName(), getNamespacePrefix());
if (sElement == null)
{
sElement = "entry";
}
PropertyAdapter adapterKey = m_adapterKey;
PropertyAdapter adapterValue = m_adapterValue;
for (Iterator iter = ((Map) o).entrySet().iterator(); iter.hasNext(); )
{
Map.Entry entry = (Map.Entry) iter.next();
XmlElement xmlEntry = xml.addElement(sElement);
List list = xmlEntry.getElementList();
Object oKey = entry.getKey();
if (oKey != null)
{
list.add(adapterKey.toXml(oKey));
}
Object oValue = entry.getValue();
if (oValue != null)
{
list.add(adapterValue.toXml(oValue));
}
}
}
// ----- ExternalizableLite helpers -------------------------------------
/**
* Read a value from the passed DataInput object.
*
* @param in the DataInput stream to read property data from
*
* @return the data read from the DataInput; never null
*
* @exception IOException if an I/O exception occurs
*/
public Object readExternal(DataInput in)
throws IOException
{
Map map = instantiateMap();
PropertyAdapter adapterKey = getKeyAdapter();
PropertyAdapter adapterVal = getValueAdapter();
// "in" contains a collection size and, for each element, a non-null
// indicator and (if non-null) the object
for (int i = 0, c = readInt(in); i < c; ++i)
{
Object oKey = (in.readBoolean() ? adapterKey.readExternal(in) : null);
Object oVal = (in.readBoolean() ? adapterVal.readExternal(in) : null);
map.put(oKey, oVal);
}
return map;
}
/**
* Write the specified data to the passed DataOutput object.
*
* @param out the DataOutput stream to write to
* @param o the data to write to the DataOutput; never null
*
* @exception IOException if an I/O exception occurs
*/
public void writeExternal(DataOutput out, Object o)
throws IOException
{
Map map = (Map) o;
PropertyAdapter adapterKey = getKeyAdapter();
PropertyAdapter adapterVal = getValueAdapter();
int c = map.size();
writeInt(out, c);
int cActual = 0;
for (Iterator iter = map.entrySet().iterator(); iter.hasNext(); )
{
Map.Entry entry = (Map.Entry) iter.next();
Object oKey = entry.getKey();
Object oVal = entry.getValue();
boolean fExists = (oKey != null);
out.writeBoolean(fExists);
if (fExists)
{
adapterKey.writeExternal(out, oKey);
}
fExists = (oVal != null);
out.writeBoolean(fExists);
if (fExists)
{
adapterVal.writeExternal(out, oVal);
}
++cActual;
}
if (c != cActual)
{
throw new IOException("expected " + c + " entries, but wrote " + cActual);
}
}
// ----- PropertyAdapter methods ----------------------------------------
/**
* Determine if the specified value is empty.
*
* @param o the value
*
* @return true if the object is considered to be empty for persistence
* and XML-generation purposes
*/
public boolean isEmpty(Object o)
{
return o == null || isEmptyIsNull() && ((Map) o).isEmpty();
}
// ----- internal helpers -----------------------------------------------
/**
* @return a PropertyAdapter for map entry keys
*/
public PropertyAdapter getKeyAdapter()
{
return m_adapterKey;
}
/**
* @return a PropertyAdapter for map entry values
*/
public PropertyAdapter getValueAdapter()
{
return m_adapterValue;
}
/**
* @return a new Map instance
*/
protected Map instantiateMap()
{
try
{
return (Map) m_clzMap.newInstance();
}
catch (Throwable e)
{
throw ensureRuntimeException(e);
}
}
// ----- data members ---------------------------------------------------
private Class m_clzMap;
private PropertyAdapter m_adapterKey;
private PropertyAdapter m_adapterValue;
}