本文介绍了JAXB 编组和泛型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 JAXB 的自省来编组和解组一些用 JAXB 注释标记的现有域对象.大多数事情都按预期工作,但我在序列化一个相当简单的类时遇到了很多麻烦.这个类在许多 bean 上用作 @XmlElement,看起来像:

public class Range>实现可序列化{protected boolean startInclusive, endInclusive;受保护的 E 开始,结束;公共范围(){startInclusive = endInclusive = true;}public boolean contains(E value){...}公共 E getEnd() {返回结束;}公共无效集结束(E结束){this.end = 结束;}公共布尔 isEndInclusive() {return endInclusive;}公共无效 setEndInclusive(boolean endInclusive) {this.endInclusive = endInclusive;}公共 E getStart() {返回开始;}public void setStart(E start) {this.start = 开始;}公共布尔 isStartInclusive() {返回 startInclusive;}public void setStartInclusive(boolean startInclusive) {this.startInclusive = startInclusive;}}

我尝试了以下操作,但没有成功,JAXB 仍然对 Comparable 接口感到愤怒.

public class DoubleRange extends Range{}

同时使用 Range 和 DoubleRange 作为 bean getter 的返回类型会产生如下异常:

java.lang.Comparable 是一个接口,JAXB 不能处理接口.此问题与以下位置有关:在 java.lang.Comparable在受保护的 java.lang.Comparable com.controlpath.util.Range.start在example.util.Range在example.util.DoubleRange在公共 example.util.DoubleRange example.domain.SomeBean.getRange()在example.domain.SomeBean

我意识到在大多数情况下 List和地图<T,U>之所以有效,是因为 JAXB 规范对在 bean 上遇到的这些类型有特殊规定,但是有什么方法可以将我想要的内容传达给 JAXB 内省引擎,而不必重新实现具有非泛型字段的范围?

解决方案

您可以通过执行以下操作来编写自定义适配器(不使用 JAXB 的 XmlAdapter):

1) 声明一个接受各种元素并带有 JAXB 注释的类并按照您的意愿处理它们(在我的示例中,我将所有内容都转换为字符串)

@YourJAXBAnnotationsGoHere公共类 MyAdapter{@XmlElement//或者 @XmlAttribute 如果你愿意私有字符串内容;公共 MyAdapter(对象输入){如果(输入实例字符串){内容=(字符串)输入;}else if(input instanceof YourFavoriteClass){content = ((YourFavoriteClass)input).convertSomehowToString();}else if(input instanceof .....){content = ((.....)input).convertSomehowToString();//等等}别的{内容 = input.toString();}}}//我建议使用 Map,IMyObjToStringConverter>...//避免令人讨厌的 if-else-instanceof 事物

2) 在要编组的类中使用这个类而不是 E

注意事项

  • 当然,这对于复杂(嵌套)数据结构不起作用.
  • 您必须考虑如何再次将其解组,这可能会更加棘手.如果这太棘手了,等待比我更好的建议;)

I am trying to use JAXB's introspection to marshall and unmashall some existing domain objects marked up with JAXB annotations. Most things work as expected, but I am having quite a bit of trouble getting a fairly simple class to serialize. This class is used as an @XmlElement on a number of beans and looks something like:

public class Range<E extends Comparable<E>> implements Serializable {
    protected boolean startInclusive, endInclusive;
    protected E       start, end;

    public Range(){
            startInclusive = endInclusive = true;
    }

    public boolean contains(E value){...}

    public E getEnd() {
            return end;
    }

    public void setEnd(E end) {
            this.end = end;
    }

    public boolean isEndInclusive() {
            return endInclusive;
    }

    public void setEndInclusive(boolean endInclusive) {
            this.endInclusive = endInclusive;
    }

    public E getStart() {
            return start;
    }

    public void setStart(E start) {
            this.start = start;
    }

    public boolean isStartInclusive() {
            return startInclusive;
    }

    public void setStartInclusive(boolean startInclusive) {
            this.startInclusive = startInclusive;
    }
}

I have tried to do the following, with no success, JAXB is still angry with the interface Comparable.

public class DoubleRange extends Range<Double> {}

Using both Range and DoubleRange as return types for the bean getter's yields an exception like:

java.lang.Comparable is an interface, and JAXB can't handle interfaces.
    this problem is related to the following location:
        at java.lang.Comparable
        at protected java.lang.Comparable com.controlpath.util.Range.start
        at example.util.Range
        at example.util.DoubleRange
        at public example.util.DoubleRange example.domain.SomeBean.getRange()
        at example.domain.SomeBean

I realize that in most cases List<T> and Map<T, U> only work because the JAXB specification has special provisions for those types when they are encountered on beans, but is there any way to convey what I want to the JAXB introspection engine without having to reimplement range with non-generic fields?

解决方案

You could write a custom adapter (not using JAXB's XmlAdapter) by doing the following:

1) declare a class which accepts all kinds of elements and has JAXB annotationsand handles them as you wish (in my example I convert everything to String)

@YourJAXBAnnotationsGoHere
public class MyAdapter{

  @XmlElement // or @XmlAttribute if you wish
  private String content;

  public MyAdapter(Object input){
    if(input instanceof String){
      content = (String)input;
    }else if(input instanceof YourFavoriteClass){
      content = ((YourFavoriteClass)input).convertSomehowToString();
    }else if(input instanceof .....){
      content = ((.....)input).convertSomehowToString();
    // and so on
    }else{
      content = input.toString();
    }
  }
}

// I would suggest to use a Map<Class<?>,IMyObjToStringConverter> ...
// to avoid nasty if-else-instanceof things

2) use this class instead of E in your to-be-marshalled class

NOTES

  • Of course this would not work for complex (nested) data structures.
  • You have to think how to unmarshall this back again, could be more tricky. Ifit's too tricky, wait for a better proposal than mine ;)

这篇关于JAXB 编组和泛型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-05 07:26