簡體   English   中英

JAXB 編組和泛型

[英]JAXB Marshalling and Generics

我正在嘗試使用 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;
    }
}

我嘗試了以下操作,沒有成功,JAXB 仍然對接口 Comparable 生氣。

public class DoubleRange extends Range<Double> {}

使用 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

我意識到在大多數情況下 List<T> 和 Map<T, U> 僅起作用,因為 JAXB 規范對在 bean 上遇到這些類型時有特殊規定,但是有什么方法可以將我想要的內容傳達給 JAXB 自省引擎而不必重新實現具有非通用字段的范圍?

您可以通過執行以下操作編寫自定義適配器(不使用JAXB的XmlAdapter):

1)聲明一個接受所有類型元素並具有JAXB注釋並根據需要處理它們的類(在我的示例中,我將所有內容轉換為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)在你的待編組課程中使用這個課程而不是E課程

筆記

  • 當然,這不會為復雜的(嵌套)數據結構工作。
  • 你必須考慮如何再次解決這個問題,可能會更棘手。 如果它太棘手了,等待比我更好的提議;)

怎么樣

public class Range<**E extends Number**> implements Serializable { ...
  • 數字是一個

  • 我敢打賭JAXB知道Number的默認編組/解組規則

對於特定類型的解組,你需要我在這里描述的XmlAdapter: JAXB繼承,unmarshal到封送類的子類

實際上,我不清楚為什么這不起作用。 似乎JAXB應該能夠正確地解析特定的子類型:if(並且僅當!)此類型不是根類型(它不是根據您的描述)。 我的意思是,它只是一個豆; 因此,如果將T替換為直接類型的bean工作,那么通用版本iff應使用子類來綁定類型(如示例中所示)。

那么也許它可能是實施中的一個錯誤?

我所做的是以下內容:

  1. 創建一個空類並將其標記為 JAXB
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public abstract class Marshallable {}
  1. 使將在泛型類中作為類型結束的每個類都擴展此 Marshallable 類型
(...)
public class A extends Marshallable {
(...)
  1. 限制你的泛型類只允許 Marshallable 的子類作為泛型類型
public class GenericType<T extends Marshallable> {
  1. 像原來一樣使用課程
A a = new A();

jaxbMarshaller.marshal(new GenericType(a), outputStream);

現在 Jaxb 將適用於所有擴展 Marshallable 的類型,甚至作為泛型類型的一部分。

嘗試像Simple XML Serialization這樣的東西,它支持XML元素中的泛型類型,帶有許多注釋,如@Element和@ElementList。 編程模型非常相似,但比JAXB更簡單。

所以看起來問題是Estartend的擦除是Comparable 如果它無法處理接口你可以嘗試Object ,但我希望它也會抱怨(現在或以后)。 可能你可以使Range抽象並為每個特定的E專門化它。 我應該更多地了解JAXB。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM