JAXB Маршаллинг и Дженерикс - PullRequest
10 голосов
/ 06 мая 2009

Я пытаюсь использовать интроспекцию JAXB для маршалинга и демонтажа некоторых существующих доменных объектов, размеченных аннотациями JAXB. Большинство вещей работает, как и ожидалось, но у меня довольно много проблем с получением довольно простого класса для сериализации. Этот класс используется как @XmlElement для ряда bean-компонентов и выглядит примерно так:

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-компонента приводит к исключению, например:

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 и Map работают только потому, что в спецификации JAXB есть специальные положения для этих типов, когда они встречаются на bean-компонентах, но есть ли способ передать то, что я хочу механизм самоанализа JAXB без необходимости переопределения диапазона с неуниверсальными полями?

Ответы [ 5 ]

5 голосов
/ 06 мая 2009

Вы можете написать собственный адаптер (не используя JAXB XmlAdapter), выполнив следующие действия:

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) используйте этот класс вместо E в вашем классе, который будет маршалом

ПРИМЕЧАНИЯ

  • Конечно, не будет работать для сложных (вложенных) структур данных.
  • Вы должны подумать, как разобрать это снова, может быть сложнее. Если это слишком сложно, ждите лучшего предложения, чем мое;)
1 голос
/ 06 мая 2009

Как насчет

public class Range<**E extends Number**> implements Serializable { ...
  • Номер класса

  • Бьюсь об заклад, JAXB знает по умолчанию правила сортировки / отмены сортировки для номера

Для демаршаллинга к определенному типу вам нужен XmlAdapter, как я здесь описано: наследование JAXB, не маршальное для подкласса маршалированного класса

0 голосов
/ 30 января 2010

На самом деле, мне не совсем понятно, почему это не сработает. Кажется, что JAXB должен быть в состоянии разрешить определенный подтип правильно: если (и только если!) Этот тип НЕ является корневым типом (который не соответствует вашему описанию). Я имею в виду, это просто Боб; поэтому, если bean-компонент с T заменен прямым типом, сработает то же самое, если общая версия iff использует подклассификацию для связывания типов (как это сделано в примере).

Так, возможно, это может быть ошибкой в ​​реализации?

0 голосов
/ 06 мая 2009

Похоже, проблема в стирании E на start, а end равно Comparable. Если он не может обрабатывать интерфейсы, вы можете попробовать Object, но я надеюсь, что он тоже будет жаловаться (сейчас или позже). Возможно, вы могли бы сделать Range абстрактным и специализировать его для каждого конкретного E. Я должен знать больше о JAXB.

0 голосов
/ 06 мая 2009

Попробуйте что-то вроде Простая сериализация XML , она поставляется с поддержкой универсальных типов в элементах XML с рядом аннотаций, таких как @Element и @ElementList. Модель программирования очень похожа, но проще, чем JAXB.

...