2014-11-16 3 views
0

Вот то, что я пытаюсь сделать:Полиморфные XML Binding с JAXB

XML заключается в следующем:

<Doctype1> 
    <Outter> 
     <Inner> 
      <ProblemType> 
       <foo>...</foo> 
       <baz>...</baz> 
      </ProblemType> 
     </Inner> 
    </Outter> 
</Doctype1> 

< - Тем не менее, у меня есть: ->

<Doctype2> 
    <Outter> 
     <Inner> 
      <ProblemType> 
       <blah>...</blah> 
       <whatever>...</whatever> 
      </ProblemType> 
     </Inner> 
    </Outter> 
</Doctype1> 

и Поделитесь большинством тех же полей, но в случае Doctype1 мне нужен ProblemType1, а в Doctype2 мне нужен ProblemType2.

Я хочу, чтобы иметь возможность повторно использовать классы, для которых я привязываю, и поскольку они являются общим тегом для всех типов документов.

@XmlAccessorType(XmlAccessType.FIELD) 
public class Doc1{ 

    @XmlElement(name = "Outter") 
    public List<Outter> outtards; 

} 

@XmlAccessorType(XmlAccessType.FIELD) 
public class Outter { 

    @XmlElement(name = "Inner") 
    public List<Innard> innards; 
} 

@XmlAccessorType(XmlAccessType.FIELD) 
public class Innard{ 

    // need to change this if it's Doc1 or Doc2. 
    //The subtype of problem type needs to change based on DocX 
    // the element type name won't change 
    @XmlElement(name = "Inner") 
    public ProblemType subtype; 
} 

Похоже, что на заводе есть на заказ?

@XmlType(factoryClass= , factoryMethod=) 
+0

Не могли бы вы также разместить 'Doc2'? И лучше сделайте это ответом - не соглашайтесь с моим и принимайте ваше. (Подумайте о будущих читателях.) – lexicore

+0

Готово. Не уверен, что это помогает будущим читателям, но хорошо. Я хочу дать вам реквизит для того, чтобы дать мне подтверждение. Я собираюсь продолжить изучение возможностей. –

+0

Это * может * помочь и правильно делать. Отлично сработано. :) – lexicore

ответ

1
@XmlAccessorType(XmlAccessType.NONE) 
    public class Doc1 { 

     @XmlElement(type = Outter1.class, name = "Outter") 
     private List<Outter> outters; 

     public static class Outter1 extends Outter { 

      @Override 
      @XmlElement(type = Inner1.class, name = "Inner") 
      public List<Inner> getInner() { 
       return super.getInner(); 
      } 

      @Override 
      public void setInner(List<Inner> innards) { 
       super.setInner(innards); 
      } 

      public static class Inner1 extends Inner<ProblemType1> { 

       @Override 
       @XmlElement(type = ProblemType1.class, name = "ProblemType") 
       public List<ProblemType> getProblemTypes() { 
        return super.getProblemTypes(); 
       } 

       @Override 
       public void setProblemTypes(List<ProblemType> problemTypes) { 
        super.setProblemTypes(problemTypes); 
       } 
      } 
     } 
    } 

другой класс

public class Doc2 { 

    @XmlElement(type = Outter2.class, name= "Outter") 
    private List<Outter> outters; 

    public static class Outter2 extends Outter { 

     @Override 
     @XmlElement(type = Outter2.class, name = "Inner") 
     public List<Inner> getInner() { 
      return super.getInner(); 
     } 

     @Override 
     public void setInner(List<Inner> innards) { 
      super.setInner(groups); 
     } 

     public static class Inner1 extends Inner<ProblemType2> { 
      @Override 
      @XmlElement(type = ProblemType2.class, name = "ProblemType") 
      public List<ProblemType> getProblemTypes() { 
       return super.getProblemTypes(); 
      } 

      @Override 
      public void setProblemTypes(List<ProblemType> transactions) { 
       super.setProblemTypes(transactions); 
      } 
     } 
    } 
} 

Я провел некоторое время, пытаясь уменьшить его, но это, кажется, не реагировать на XmlAccesorType.FIELD. Если я использую то же имя свойства, что и супер, или нет, это не имеет значения.

+0

Выглядит хорошо. Отлично сработано. Также попробуйте поэкспериментировать с '@ XmlElementWrapper', возможно, вы можете сохранить один уровень (т. Е.« Outter'). – lexicore

+0

Опубликовать следующее? Хотелось бы сэкономить несколько строк. –

+0

Конечно, [здесь вы идете] (http://stackoverflow.com/a/26989483/303810). – lexicore

1

Прежде всего, как бы вы реализовали такую ​​структуру на Java? Есть некоторое расстояние между DoctypeX и ProblemTypeX, поэтому вы не можете полиформировать напрямую.

Вероятно, со структурой типа (очень псевдо-код):

class AbstractDoctype { 
    AbstractOuter getOuter(); 
} 
class AbstractOuter { 
    AbstractInner getInner(); 
} 
class AbstractInner { 
    AbstractProblemType getProblemType(); 
} 
class AbstractProblemType { 
} 

class Doctype1 extends AbstractDoctype { 
    Outer1 getOuter(); 
} 
class Outer1 extends AbstractOuter { 
    Inner1 getInner(); 
} 
class Inner1 extends AbstractInner { 
    ProblemType1 getProblemType(); 
} 
class ProblemType1 extends AbstractProblemType { 
} 

class Doctype2 extends AbstractDoctype { 
    Outer2 getOuter(); 
} 
class Outer2 extends AbstractOuter { 
    Inner2 getInner(); 
} 
class Inner2 extends AbstractInner { 
    ProblemType2 getProblemType(); 
} 
class ProblemType2 extends AbstractProblemType { 
} 

Такая структура будет затем подходит для XML. Вероятно, вы можете избежать Outer1/Outer2, используя @XmlElementWrapper, но вам все равно потребуется Inner1/Inner2.

+0

Я обновил описание проблемы. Я понял, что прошлой ночью это было не очень ясно, поэтому я обновил его. прямо сейчас. У вашей идеи могут быть некоторые заслуги. Только «ProblemType» нуждается в изменении, но я не вижу способа сделать это, не делая все, что вы говорите. –

+0

@ChristianBongiorno Я проверил ваше редактирование - я думаю, это не имеет никакого значения для моего ответа. Моя точка зрения все еще стоит. Вам нужно будет полиформировать промежуточные классы. Я не вижу другого пути. И попробуйте подумать, как вы это сделаете на Java. – lexicore

+0

Возможно, вы правы. Я не мог думать ни о каком другом пути, но думал, что брошу его туда и посмотрю, сможет ли кто-нибудь, кто умнее меня, ответить –

0

Выполнение этой задачи до this answer с целью экономии нескольких строк с @XmlElementWrapper. Поскольку Outter класса, кажется, не имеет никакого смысла, сами по себе, и он служит только в качестве контейнера для Inner класса, его можно избежать:

Пожалуйста, попробуйте следующее:

@XmlAccessorType(XmlAccessType.NONE) 
public class Doc1 { 

     @XmlElementWrapper(name = "Outter") 
     @XmlElement(type = Inner1.class, name = "Inner") 
     public List<Inner> getInner() { 
      return super.getInner(); 
     } 

     @Override 
     public void setInner(List<Inner> innards) { 
      super.setInner(innards); 
     } 

     public static class Inner1 extends Inner<ProblemType1> { 

      @Override 
      @XmlElement(type = ProblemType1.class, name = "ProblemType") 
      public List<ProblemType> getProblemTypes() { 
       return super.getProblemTypes(); 
      } 

      @Override 
      public void setProblemTypes(List<ProblemType> problemTypes) { 
       super.setProblemTypes(problemTypes); 
      } 
     } 
} 

Однако в голове, что это сейчас один список, а не список списков. Так что это должно быть по-прежнему можно с этой конструкцией:

<Doctype1> 
    <Outter> 
     <Inner> 
      <ProblemType .../> 
     </Inner> 
     <Inner> 
      <ProblemType .../> 
     </Inner> 
    </Outter> 
</Doctype1> 

Но это не так:

<Doctype1> 
    <Outter> 
     <Inner> 
      <ProblemType .../> 
     </Inner> 
    </Outter> 
    <Outter> 
     <Inner> 
      <ProblemType .../> 
     </Inner> 
    </Outter> 
</Doctype1> 
+0

О, Outter имеет смысл. Он содержит, как, 15 значений, которые я пропустил ради краткости :) Имеет ли это значение? Позвольте мне сказать это –

+0

@ChristianBongiorno OK, тогда вы не можете его пропустить, извините. :) – lexicore