java JAXB 编组和泛型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/826736/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 13:56:48  来源:igfitidea点击:

JAXB Marshalling and Generics

javagenericsjaxb

提问by Steve Skrla

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:

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

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.

我尝试了以下操作,没有成功,JAXB 仍然对接口 Comparable 生气。

public class DoubleRange extends Range<Double> {}

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

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

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?

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

采纳答案by ivan_ivanovich_ivanoff

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

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

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

1) 声明一个类,它接受各种元素并具有 JAXB 注释并根据需要处理它们(在我的示例中,我将所有内容都转换为字符串)

@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

2)在您要编组的类中使用此类而不是 E

NOTES

笔记

  • Of course this would notwork for complex (nested) data structures.
  • You have to think how to unmarshall this back again, could be more tricky. If it's too tricky, wait for a better proposal than mine ;)
  • 当然,这不适用于复杂的(嵌套)数据结构。
  • 您必须考虑如何再次将其解组,这可能会更加棘手。如果太棘手,请等待比我更好的建议;)

回答by ivan_ivanovich_ivanoff

How about

怎么样

public class Range<**E extends Number**> implements Serializable { ...
  • Number is a class

  • I bet JAXB knows defaultmarshalling/unmarshalling rules for Number

  • 数字是一个

  • 我敢打赌 JAXB 知道Number 的默认编组/解组规则

For unmarshalling to specific type, you need XmlAdapter as I described here: JAXB inheritance, unmarshal to subclass of marshaled class

要解组到特定类型,您需要 XmlAdapter,正如我在此处描述的:JAXB 继承,解组到已编组类的子类

回答by StaxMan

Actually, it is not quite clear to me why this would not work. It seems like JAXB should be able to resolve specific subtype correctly: if (and only if!) this type is NOT the root type (which it is not as per your description). I mean, it is just a Bean; so if bean with T replaced with direct type works, so should generic version iff using sub-classing to bind types (as is done in example).

实际上,我不太清楚为什么这行不通。似乎 JAXB 应该能够正确解析特定的子类型:如果(且仅当!)此类型不是根类型(这与您的描述不同)。我的意思是,它只是一个 Bean;因此,如果使用直接类型替换 T 的 bean 有效,那么泛型版本 iff 也应该使用子类来绑定类型(如示例中所做的那样)。

So perhaps it could be a bug in implementation?

那么也许它可能是实现中的错误?

回答by ng.

Try something like Simple XML Serializationit comes with support for generic types in XML elements with a number of annotations such as @Element and @ElementList. The programming model is very similar, but simpler than JAXB.

尝试像Simple XML Serialization这样的东西,它支持 XML 元素中的泛型类型,带有许多注释,例如 @Element 和 @ElementList。编程模型非常相似,但比 JAXB 简单。

回答by Tom Hawtin - tackline

So it looks like the problem is the erasure of Eon startand endis Comparable. If it can't handle interfaces you could try Object, but I would hope it complains at that too (either now or later). Possibly you could make Rangeabstract and specialise it for each specific E. I should know more about JAXB.

所以看起来问题是擦除Eonstartendis Comparable。如果它无法处理接口,您可以尝试Object,但我希望它也抱怨(现在或以后)。可能您可以将其Range抽象化并针对每个特定的E. 我应该更多地了解 JAXB。