JAXB / Moxy将XmlElements与XmlAdapter一起使用

时间:2013-10-09 07:51:54

标签: java eclipselink marshalling jaxb2 moxy

我尝试使用MOXy完成此question中描述的内容。 但我有一些不同的行为,但结果是一样的。它不起作用。

我使用@XmlElements,对于每个concret类,我添加了一个名称和类型的@XmlElement。 对于没有适配器的所有类,它都是完美的,但不适用于使用PolyAdapter的类。

在我的情况下,将调用适配器来封送对象。但它写的所有内容都是这样的条目到xml文件中。

<?xml version="1.0" encoding="UTF-8"?>
<fooContainer>
  <poly PolyName="PolyN$1">ABCBCD</poly>
  <cPlexPoly>moxy.CPlexPoly$CPlexPolyAdapter$CCPWrapper@480bdb19</cPlexPoly>
</fooContainer>

根本不会召唤unmarshaller。

我在两种情况下测试了MOXy 2.5.0和当前的RC3 2.5.1,结果是相同的。 我也启用了调试输出,没有警告或错误。

或许还有另一种方法可以实现这个目标

更新1:提供型号

我创建了一个显示我的MOXy 2.5.0问题的小例子

接口:

@XmlRootElement
public interface Foo {
  public List<String> getCoordinates();
}

没有XmlAdapter的类:

@XmlRootElement(name="poly")
public class Poly implements Foo {
  @XmlAttribute
  String PolyName = "PolyN$1";

  @XmlAnyElement
  private List<String> coordinates = new LinkedList<>();

  @Override
  public List<String> getCoordinates() {
    return coordinates;
  }

  public void addCoordinate( final String poly ) {
    coordinates.add( poly );
  }
}

使用XmlAdapter的类:

@XmlJavaTypeAdapter(CPlexPolyAdapter.class)
public class CPlexPoly implements Foo {
private Map<String, String> values = new HashMap<>();

@Override
public List<String> getCoordinates() {
  return new ArrayList<>(values.values());
}

public void addCoordinate( final String poly ) {
  values.put( Integer.toString( poly.hashCode()), poly );
}

public List<String> getKeys() {
  return new ArrayList<>(values.keySet());
}


public static class CPlexPolyAdapter extends XmlAdapter<CCPWrapper, CPlexPoly> {

  @XmlRootElement(name="wrapper")
  public static class CCPWrapper {
    @XmlAnyElement
    List<String> keys = new ArrayList<>();
    @XmlAnyElement
    List<String> values = new ArrayList<>();
  }

  @Override
  public CPlexPoly unmarshal(CCPWrapper v) throws Exception {
    // Won't be called. 
    return null;
  }

  @Override
  public CCPWrapper marshal(CPlexPoly v) throws Exception {
    if( v == null ) {
      return null;
    }

    CCPWrapper wrapper = new CCPWrapper();
    wrapper.values.addAll( v.getCoordinates() );
    wrapper.keys.addAll( v.getKeys() );

    return wrapper;
  } 
}
}

简单容器类:

@XmlRootElement(name="fooContainer") 
public class FooContainer {

  @XmlElements({
    @XmlElement(name = "poly", type = Poly.class),
    @XmlElement(name = "cPlexPoly", type = CPlexPoly.class)
  })
  public List<Foo> container = new LinkedList<>();
}

主:

public class Main {
  public static void main(String[] args) {
    FooContainer fc = new FooContainer();

    Poly poly = new Poly();
    poly.addCoordinate("ABC");
    poly.addCoordinate("BCD");

    CPlexPoly cpoly = new CPlexPoly();
    cpoly.addCoordinate("XYZ");
    cpoly.addCoordinate("WXY");

    fc.container.add( poly );
    fc.container.add( cpoly );

    /* Marshall */
    JAXBContext context;
    try {
      context = JAXBContext.newInstance( FooContainer.class );
      Marshaller marshaller = context.createMarshaller();
      marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
      marshaller.marshal( fc, new FileWriter("fc.xml") );
    } 
    catch (JAXBException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }

    /* UnMarshall */
  }
}

我还更新了上面描述的结果。 THX。

更新2:简化包装

即使这个简单的包装器只包含一个属性,也没有任何变化。

@XmlJavaTypeAdapter(CPlexPolyAdapter.class)
public class CPlexPoly implements Foo {

  private Map<String, String> values = new HashMap<>();

  @Override
  public List<String> getCoordinates() {
    return new ArrayList<>(values.values());
  }

  public void addCoordinate( final String poly ) {
    values.put( Integer.toString( poly.hashCode()), poly );
  }

  public List<String> getKeys() {
    return new ArrayList<>(values.keySet());
  }


  public static class CPlexPolyAdapter extends XmlAdapter<CCPWrapper, CPlexPoly> {

    @XmlRootElement(name="wrapper")
    public static class CCPWrapper {

      @XmlAttribute
      String test = "test";
    }

    @Override
    public CPlexPoly unmarshal(CCPWrapper v) throws Exception {
      // Won't be called. 
      return null;
    }

    @Override
    public CCPWrapper marshal(CPlexPoly v) throws Exception {
      if( v == null ) {
        return null;
      }

      CCPWrapper wrapper = new CCPWrapper();
      return wrapper;
    }
  }
}

因此,如果有人知道出了什么问题,那将非常有帮助。 谢谢 基督教

1 个答案:

答案 0 :(得分:1)

注意:我是EclipseLink JAXB (MOXy)主管,是JAXB (JSR-222)专家组的成员。

您遇到的问题是由于CCPWrapper类未正确映射。您不能使用@XmlAnyElement映射两个字段/属性。

    @XmlRootElement(name = "wrapper")
    public static class CCPWrapper {
        @XmlAnyElement
        List<String> keys = new ArrayList<>();
        @XmlAnyElement
        List<String> values = new ArrayList<>();
    }

当我修改代码以删除其中一个@XmlAnyElement注释时,一切似乎都正常工作。


更新#1

  

感谢您的回答。但不,我仍然得到相同的输出。我什至   使用XmlAnyElement注释删除了两个列表,并添加了一个   简单的XmlAttribute。输出不会改变。查看更新   有问题的包装类。

我刚刚注意到,当我尝试使用代码时,我已将CPlexPoly类型的字段添加到FooContainer类。除了我之前的建议之外,还会将XmlAdapter应用于container字段。

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement(name = "fooContainer")
public class FooContainer {

    @XmlElement
    private final CPlexPoly workaround = null;

    @XmlElements({ 
        @XmlElement(name = "poly", type = Poly.class),
        @XmlElement(name = "cPlexPoly", type = CPlexPoly.class) 
    })
    public List<Foo> container = new LinkedList<>();

}

您可以采取与解决方法类似的方法。我打开了以下错误,您可以使用它来跟踪我们在实际修复方面的进展:


更新#2

更好的解决方法是在用于创建CCPWrapper的类中包含JAXBContext类,如下所示:

    context = JAXBContext.newInstance( FooContainer.class, CCPWrapper.class );