【问题标题】:JAXB : How to remove wrapping tag when using MapJAXB:使用 Map 时如何删除包装标签
【发布时间】:2016-06-17 10:40:52
【问题描述】:

我在编组时使用@XmlJavaTypeAdapterMap<Key, Value> 对象转换为List<Value>,反之则在取消编组时

然后是我得到的XML:

<map>
    <value>VALUE1</value>
...
</map>

我的问题是:我怎样才能摆脱周围的标签以获得

<value>VALUE1</value>

Bean 类

@XmlAccessorType(XmlAccessType.FIELD)
public class Data implements Serializable {

  /**
   * Constant for data value default name
   */
  public static final String DATA_VALUE_DEFAULT_NAME = "result";

  /**
   * Serial version UID
   */
  private static final long serialVersionUID = 7387937212735185585L;

  /**
   * key
   */
  @XmlAttribute
  private String key;

  /**
   * name
   */
  @XmlAttribute
  private String name;

  /**
   * Map of data
   */
  @XmlJavaTypeAdapter(MapDataAdapter.class)
  private Map<String, Data> dataMap;

  /**
   * Constructor
   */
  public Data() {

  }
}

适配器

public class MapDataAdapter 
  extends XmlAdapter<MapDataAdapter.AdaptedDataMap,
                     Map<String, Data>> {

  /**
   * Adapted map
   */
  public static class AdaptedDataMap {

    /**
     * List of entry
     */
    @XmlElement(name = "data", required = true)
    protected List<Data> entry = new ArrayList<>();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Map<String, Data> unmarshal(
    AdaptedDataMap adaptedMap) throws Exception {
    if (adaptedMap == null) {
     return null;
    }
    Map<String, Data> map = new HashMap<>(adaptedMap.entry.size());
    for (Data entry : adaptedMap.entry) {
      map.put(entry.getKey(), entry);
    }
    return map;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public AdaptedDataMap marshal(
      Map<String, Data> map) throws Exception {
    if (map == null) {
      return null;
    }
    AdaptedDataMap adaptedMap = new AdaptedDataMap();
    for (Entry<String, Data> mapEntry : map.entrySet()) {
      adaptedMap.entry.add(mapEntry.getValue());
    }
    return adaptedMap;
  }
}

XML 输出

<data key="12" name="TEST1">
    <dataMap>
        <data key="text" name="TEST2">
            <dataMap>
                <data key="azerty" name="TEST3">
                </data>
            </dataMap>
        </data>
    </dataMap>
</data>

我需要什么

<data key="12" name="TEST1">
    <data key="text" name="TEST2">
            <data key="azerty" name="TEST3">
            </data>
    </data>
</data>

【问题讨论】:

标签: java xml jaxb


【解决方案1】:

JAXB 映射/带继承/不带元素包装器

要在没有元素包装器的情况下从/到地图中编组/解组元素,您可以实现一个将数据存储在地图中的列表。 JAXB 会将其视为一个简单的列表,并且知道如何处理它。

我开发这种方法是因为@XmlJavaTypeAdapter 似乎与@XmlElements@XmlElementRefs 不兼容。实际上,javadocs 说 @XmlJavaTypeAdapter 可以与 @XmlElementRefs 结合使用,但它对我不起作用。我一直在捕捉 ClassCastException。

替代方案一次解决了两个问题:

  • 不需要元素包装器
  • 允许使用@XmlElements 映射

ExampleDocument.java

@XmlRootElement(name="example-document")
@XmlAccessorType(XmlAccessType.NONE)
public class ExampleDocument
{
  @XmlElements
  (
    {
      @XmlElement( name="child1" type=Child1.class ),
      @XmlElement( name="child2", type=Child2.class )
    }
  )
  private ChildrenList children = new ChildrenList();

  public Children getChildById( String id ) 
  { 
    return children.getMap().get( id ); 
  }
  public Collection<Children> allChildren()
  {
    return children.getMap().values();
  }
}

Children.java

@XmlTransient
public class Children
{
  private String id;
}

Child1.java

@XmlType
public class Child1 extends Children
{
}

Child2.java

@XmlType
public class Child2 extends Children
{
}

ChildrenList.java

public class ChildList implements List<Children>
{
  private Map<String,Children> map 
     = new TreeMap<String,Children>();

  @Override
  public boolean add( Children c ) 
  {
    return map.put( c.getId(), c ) != null;
  }
  @Override
  public boolean remove( Object o )
  {
    return map.remove( ((Children)o).getId() ) != null;
  }
  @Override
  public int size()
  {
    return map.size();
  }
  @Override
  public boolean isEmpty()
  {
    return map.isEmpty();
  }
  @Override
  public boolean contains( Object o )
  {
    return map.containsKey( ((Children)o).getId() );
  }
  @Override
  public Iterator<Children> iterator()
  {
    return map.values().iterator();
  }
  @Override
  public Object[] toArray()
  {
    return map.values().toArray();
  }
  @Override
  public <T> T[] toArray( T[] ts )
  {
    return map.values().toArray( ts );
  }
  @Override
  public boolean addAll( Collection<? extends ArticleBiblio> collection )
  {
    boolean result = false;
    for( ArticleBiblio b : collection )
    {
      result |= add( b );
    }
    return result;
  }

  /* all other methods throws UnsupportedOperationException */
}

【讨论】:

    【解决方案2】:

    我喜欢 Lucas 的解决方案,并在这里对其进行了扩展,使其成为通用的,以防止不必要的类型检查。

    列表项抽象类

    abstract class MapListItem<K> {
        /* Note that we can't implement this here, because we may want to rename or restructure the key attribute in the XML */
        public abstract K getKey();
    }
    

    示例项目类

    public class ItemA extends MapListItem<String>{
        @XmlAttribute(name="keyA")
        public String key;
        @XmlElement(name = "valueA")
        public ArrayList<ValueA> values = new ArrayList<>();
    
        public ItemA(String key) {
            this.key = key;
        }
    
        public ItemA(String key, ArrayList<ValueA> values) {
            this(key);
            this.values = values;
        }
    
        @Override
        public String getKey() {
            return key;
        }
    
    }
    

    Genericized Map List - K 是键类型,V 是值类型,其中也包含一个键。

    public class MapList<K, V extends MapListItem<K>> implements List<V> {
        private Map<K, V> map = new TreeMap<>();
    
        public MapList(Collection<? extends V> collection) {
            addAll(collection);
        }
    
        @Override
        public boolean add(V c) {
            return map.put(c.getKey(), c) != null;
        }
    
        @Override
        public boolean remove(Object o) {
            return map.remove(((V) o).getKey()) != null;
        }
    
        @Override
        public int size() {
            return map.size();
        }
    
        @Override
        public boolean isEmpty() {
            return map.isEmpty();
        }
    
        @Override
        public boolean contains(Object o) {
            return map.containsKey(((V) o).getKey());
        }
    
        @Override
        public Iterator<V> iterator() {
            return map.values().iterator();
        }
    
        @Override
        public Object[] toArray() {
            return map.values().toArray();
        }
    
        @Override
        public <T> T[] toArray(T[] ts) {
            return map.values().toArray(ts);
        }
    
        @Override
        public boolean addAll(Collection<? extends V> collection) {
            boolean result = false;
            for (V b : collection) {
                result |= add(b);
            }
            return result;
        }
    }
    

    现在我们可以像这样制作一个 MapList:

    @XmlElement(name = "itemA")
    public MapList<String,ItemA> itemAs;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多