All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.thoughtworks.xstream.converters.extended.NamedMapConverter Maven / Gradle / Ivy

There is a newer version: 0.40.13
Show newest version
/*
 * Copyright (C) 2013, 2016 XStream Committers.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 * Created on 20. September 2013 by Joerg Schaible
 */
package com.thoughtworks.xstream.converters.extended;

import java.util.Iterator;
import java.util.Map;

import com.thoughtworks.xstream.converters.ConversionException;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.ConverterLookup;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.SingleValueConverter;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.converters.collections.MapConverter;
import com.thoughtworks.xstream.core.JVM;
import com.thoughtworks.xstream.core.util.HierarchicalStreams;
import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.mapper.Mapper;


/**
 * A map converter that uses predefined names for its elements.
 * 

* To be used as local converter. Note, suppress the usage of the implicit type argument, if * registered with annotation. Depending on the constructor arguments it is possible to support * various formats: *

*
    *
  • new NamedMapConverter(xstream.getMapper(), "entry", "key", String.class, "value", * Integer.class); * *
     * <map>
     *   <entry>
     *     <key>keyValue</key>
     *     <value>0</value>
     *   </entry>
     * </map>
     * 
    * *
  • *
  • new NamedMapConverter(xstream.getMapper(), null, "key", String.class, "value", * Integer.class); * *
     * <map>
     *   <key>keyValue</key>
     *   <value>0</value>
     * </map>
     * 
    * *
  • *
  • new NamedMapConverter(xstream.getMapper(), "entry", "key", String.class, "value", * Integer.class, true, true, xstream.getConverterLookup()); * *
     * <map>
     *   <entry> key="keyValue" value="0"/>
     * </map>
     * 
    * *
  • *
  • new NamedMapConverter(xstream.getMapper(), "entry", "key", String.class, "value", * Integer.class, true, false, xstream.getConverterLookup()); * *
     * <map>
     *   <entry key="keyValue">
     *     <value>0</value>
     *   </entry>
     * </map>
     * 
    * *
  • *
  • new NamedMapConverter(xstream.getMapper(), "entry", "key", String.class, "value", * Integer.class, false, true, xstream.getConverterLookup()); * *
     * <map>
     *   <entry value="0">
     *     <key>keyValue</key>
     *   </entry>
     * </map>
     * 
    * *
  • *
  • new NamedMapConverter(xstream.getMapper(), "entry", "key", String.class, null, * Integer.class, true, false, xstream.getConverterLookup()); * *
     * <map>
     *   <entry key="keyValue">0</entry>
     * </map>
     * 
    * *
  • *
* * @author Jörg Schaible * @since 1.4.5 */ public class NamedMapConverter extends MapConverter { private final String entryName; private final String keyName; private final Class keyType; private final String valueName; private final Class valueType; private final boolean keyAsAttribute; private final boolean valueAsAttribute; private final ConverterLookup lookup; private final Mapper enumMapper; /** * Constructs a NamedMapConverter. * * @param mapper the mapper * @param entryName the name of the entry elements * @param keyName the name of the key elements * @param keyType the base type of key elements * @param valueName the name of the value elements * @param valueType the base type of value elements * @since 1.4.5 */ public NamedMapConverter( Mapper mapper, String entryName, String keyName, Class keyType, String valueName, Class valueType) { this(mapper, entryName, keyName, keyType, valueName, valueType, false, false, null); } /** * Constructs a NamedMapConverter handling an explicit Map type. * * @param type the Map type this instance will handle * @param mapper the mapper * @param entryName the name of the entry elements * @param keyName the name of the key elements * @param keyType the base type of key elements * @param valueName the name of the value elements * @param valueType the base type of value elements * @since 1.4.5 */ public NamedMapConverter( Class type, Mapper mapper, String entryName, String keyName, Class keyType, String valueName, Class valueType) { this( type, mapper, entryName, keyName, keyType, valueName, valueType, false, false, null); } /** * Constructs a NamedMapConverter with attribute support. * * @param mapper the mapper * @param entryName the name of the entry elements * @param keyName the name of the key elements * @param keyType the base type of key elements * @param valueName the name of the value elements * @param valueType the base type of value elements * @param keyAsAttribute flag to write key as attribute of entry element * @param valueAsAttribute flag to write value as attribute of entry element * @param lookup used to lookup SingleValueConverter for attributes * @since 1.4.5 */ public NamedMapConverter( Mapper mapper, String entryName, String keyName, Class keyType, String valueName, Class valueType, boolean keyAsAttribute, boolean valueAsAttribute, ConverterLookup lookup) { this( null, mapper, entryName, keyName, keyType, valueName, valueType, keyAsAttribute, valueAsAttribute, lookup); } /** * Constructs a NamedMapConverter with attribute support handling an explicit Map type. * * @param type the Map type this instance will handle * @param mapper the mapper * @param entryName the name of the entry elements * @param keyName the name of the key elements * @param keyType the base type of key elements * @param valueName the name of the value elements * @param valueType the base type of value elements * @param keyAsAttribute flag to write key as attribute of entry element * @param valueAsAttribute flag to write value as attribute of entry element * @param lookup used to lookup SingleValueConverter for attributes * @since 1.4.5 */ public NamedMapConverter( Class type, Mapper mapper, String entryName, String keyName, Class keyType, String valueName, Class valueType, boolean keyAsAttribute, boolean valueAsAttribute, ConverterLookup lookup) { super(mapper, type); this.entryName = entryName != null && entryName.length() == 0 ? null : entryName; this.keyName = keyName != null && keyName.length() == 0 ? null : keyName; this.keyType = keyType; this.valueName = valueName != null && valueName.length() == 0 ? null : valueName; this.valueType = valueType; this.keyAsAttribute = keyAsAttribute; this.valueAsAttribute = valueAsAttribute; this.lookup = lookup; enumMapper = JVM.is15() ? UseAttributeForEnumMapper.createEnumMapper(mapper) : null; if (keyType == null || valueType == null) { throw new IllegalArgumentException("Class types of key and value are mandatory"); } if (entryName == null) { if (keyAsAttribute || valueAsAttribute) { throw new IllegalArgumentException( "Cannot write attributes to map entry, if map entry must be omitted"); } if (valueName == null) { throw new IllegalArgumentException( "Cannot write value as text of entry, if entry must be omitted"); } } if (keyName == null) { throw new IllegalArgumentException("Cannot write key without name"); } if (valueName == null) { if (valueAsAttribute) { throw new IllegalArgumentException( "Cannot write value as attribute without name"); } else if (!keyAsAttribute) { throw new IllegalArgumentException( "Cannot write value as text of entry, if key is also child element"); } } if (keyAsAttribute && valueAsAttribute && keyName.equals(valueName)) { throw new IllegalArgumentException( "Cannot write key and value with same attribute name"); } } public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { Map map = (Map)source; SingleValueConverter keyConverter = null; SingleValueConverter valueConverter = null; if (keyAsAttribute) { keyConverter = getSingleValueConverter(keyType, "key"); } if (valueAsAttribute || valueName == null) { valueConverter = getSingleValueConverter(valueType, "value"); } for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) { Map.Entry entry = (Map.Entry)iterator.next(); Object key = entry.getKey(); Object value = entry.getValue(); if (entryName != null) { ExtendedHierarchicalStreamWriterHelper.startNode( writer, entryName, entry.getClass()); if (keyConverter != null && key != null) { writer.addAttribute(keyName, keyConverter.toString(key)); } if (valueName != null && valueConverter != null && value != null) { writer.addAttribute(valueName, valueConverter.toString(value)); } } if (keyConverter == null) { writeItem(keyName, keyType, key, context, writer); } if (valueConverter == null) { writeItem(valueName, valueType, value, context, writer); } else if (valueName == null) { writer.setValue(valueConverter.toString(value)); } if (entryName != null) { writer.endNode(); } } } protected void populateMap(HierarchicalStreamReader reader, UnmarshallingContext context, Map map, Map target) { SingleValueConverter keyConverter = null; SingleValueConverter valueConverter = null; if (keyAsAttribute) { keyConverter = getSingleValueConverter(keyType, "key"); } if (valueAsAttribute || valueName == null) { valueConverter = getSingleValueConverter(valueType, "value"); } while (reader.hasMoreChildren()) { Object key = null; Object value = null; if (entryName != null) { reader.moveDown(); if (keyConverter != null) { String attribute = reader.getAttribute(keyName); if (attribute != null) { key = keyConverter.fromString(attribute); } } if (valueAsAttribute && valueConverter != null) { String attribute = reader.getAttribute(valueName); if (attribute != null) { value = valueConverter.fromString(attribute); } } } if (keyConverter == null) { reader.moveDown(); if (valueConverter == null && !keyName.equals(valueName) && reader.getNodeName().equals(valueName)) { value = readItem(valueType, reader, context, map); } else { key = readItem(keyType, reader, context, map); } reader.moveUp(); } if (valueConverter == null) { reader.moveDown(); if (keyConverter == null && key == null && value != null) { key = readItem(keyType, reader, context, map); } else { value = readItem(valueType, reader, context, map); } reader.moveUp(); } else if (!valueAsAttribute) { value = valueConverter.fromString(reader.getValue()); } target.put(key, value); if (entryName != null) { reader.moveUp(); } } } private SingleValueConverter getSingleValueConverter(Class type, String part) { SingleValueConverter conv = UseAttributeForEnumMapper.isEnum(type) ? enumMapper .getConverterFromItemType(null, type, null) : mapper().getConverterFromItemType( null, type, null); if (conv == null) { Converter converter = lookup.lookupConverterForType(type); if (converter instanceof SingleValueConverter) { conv = (SingleValueConverter)converter; } else { throw new ConversionException("No SingleValueConverter for " + part + " available"); } } return conv; } protected void writeItem(String name, Class type, Object item, MarshallingContext context, HierarchicalStreamWriter writer) { Class itemType = item == null ? Mapper.Null.class : item.getClass(); ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, itemType); if (!itemType.equals(type)) { String attributeName = mapper().aliasForSystemAttribute("class"); if (attributeName != null) { writer.addAttribute(attributeName, mapper().serializedClass(itemType)); } } if (item != null) { context.convertAnother(item); } writer.endNode(); } protected Object readItem(Class type, HierarchicalStreamReader reader, UnmarshallingContext context, Object current) { String className = HierarchicalStreams.readClassAttribute(reader, mapper()); Class itemType = className == null ? type : mapper().realClass(className); if (Mapper.Null.class.equals(itemType)) { return null; } else { return context.convertAnother(current, itemType); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy