简体   繁体   English

使用XmlElement和XmlAdapter的JAXB / Moxy

[英]JAXB/Moxy Using XmlElements with XmlAdapter

I try to do exactly what is descripted in this question with MOXy. 我尝试使用MOXy完全执行此问题中描述的操作。 But i have some different behavior but the result is the same. 但是我有一些不同的行为,但结果是相同的。 It doesn't work. 没用

I use @XmlElements and for each concret class I added a @XmlElement with name and type. 我使用@XmlElements,并为每个具体的类添加一个名称和类型为@XmlElement的对象。 For all classes without an adapter it works perfect but not for the class with the PolyAdapter. 对于没有适配器的所有类,它都可以完美地工作,但不适用于带有PolyAdapter的类。

In my case the adapter will be called to marshal the object. 在我的情况下,将调用适配器封送对象。 But all it writes is an entry like this into the xml file. 但是它所写的只是在xml文件中的一个这样的条目。

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

And the unmarshaller won't be called at all. 解组员根本不会被召唤。

I tested MOXy 2.5.0 and the current RC3 2.5.1 in both cases the results are the same. 在两种情况下,我测试了MOXy 2.5.0和当前的RC3 2.5.1,结果是相同的。 I also enabled the debug output and there are no warnings or error. 我还启用了调试输出,并且没有警告或错误。

Or maybe there is another way to get this working 也许还有另一种方法可以使此工作

Update 1: Providing model 更新1:提供模型

I created a small example showing my problem with MOXy 2.5.0 我创建了一个小示例来说明我的MOXy 2.5.0问题

Interface: 接口:

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

Class without XmlAdapter: 没有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 );
  }
}

Class with XmlAdapter: 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;
  } 
}
}

Simple container class: 简单容器类:

@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<>();
}

Main: 主要:

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 */
  }
}

I also updated the result i described above. 我也更新了我上面描述的结果。 Thx. 谢谢。

Update 2: Simplified Wrapper 更新2:简化包装

Even with this simple wrapper containing nothing more than an attribute, nothing changes. 即使这个简单的包装器只包含一个属性,也没有任何变化。

@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;
    }
  }
}

So if someone has any idea what is wrong it would be very helpful. 因此,如果有人有什么错,那将非常有帮助。 Thanks Christian 谢谢克里斯蒂安

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group. 注意:我是EclipseLink JAXB(MOXy)的负责人,并且是JAXB(JSR-222)专家组的成员。

The problem you are encountering is due to the CCPWrapper class being mapped incorrectly. 您遇到的问题是由于CCPWrapper类映射不正确。 You are not allowed to have two fields/properties mapped with @XmlAnyElement . 不允许使用@XmlAnyElement映射两个字段/属性。

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

When I modified your code to remove one of the @XmlAnyElement annotations everything appeared to work correctly. 当我修改您的代码以删除@XmlAnyElement批注之一时,一切似乎都可以正常工作。


UPDATE #1 更新#1

Thank you for your answer. 谢谢您的回答。 But no I still get the same output. 但是不,我仍然得到相同的输出。 I even removed both lists with the XmlAnyElement annotation and just added a simple XmlAttribute. 我什至用XmlAnyElement批注删除了两个列表,只是添加了一个简单的XmlAttribute。 The output doesn't change. 输出不变。 See the updated Wrapper class in question. 请参阅有问题的更新的Wrapper类。

I just noticed that when I was trying out your code that I had added a field of type CPlexPoly to the FooContainer class. 我只是注意到,当我尝试使用您的代码时,我向FooContainer类添加了一个CPlexPoly类型的字段。 This in addition to my previous suggestion caused the XmlAdapter to be applied to the container field. 除了我以前的建议之外,这还导致将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<>();

}

You could do something similar as a workaround. 您可以执行类似的操作来解决。 I have opened the following bug that you can use to track our progress on the real fix: 我打开了以下错误,您可以使用该错误来跟踪我们在实际修复中的进度:


UPDATE #2 更新#2

A better workaround would be to include the CCPWrapper class in the classes used to create the JAXBContext as follows: 更好的解决方法是将CCPWrapper类包含在用于创建JAXBContext的类中,如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM