2012-06-20 3 views
7

JAXB는 쓰는 것을 읽을 수 없습니다. 다음 코드를 고려하십시오.JAXB는 인터페이스 목록을 비 정렬 화하지 않습니다.

interface IFoo { 
    void jump(); 
} 

@XmlRootElement 
class Bar implements IFoo { 
    @XmlElement 
    public String y; 

    public Bar() { 
     y = ""; 
    } 

    public Bar(String y) { 
     this.y = y; 
    } 

    @Override 
    public void jump() { 
     System.out.println(y); 
    } 
} 

@XmlRootElement 
class Baz implements IFoo { 
    @XmlElement 
    public int x; 

    public Baz() { 
     x = 0; 
    } 

    public Baz(int x) { 
     this.x = x; 
    } 

    @Override 
    public void jump() { 
     System.out.println(x); 
    } 
} 

@XmlRootElement 
public class Holder { 
    private List<IFoo> things; 

    public Holder() { 
     things = new ArrayList<>(); 
    } 

    @XmlElementWrapper 
    @XmlAnyElement 
    public List<IFoo> getThings() { 
     return things; 
    } 

    public void addThing(IFoo thing) { 
     things.add(thing); 
    } 
} 

// ... 

try { 
    JAXBContext context = JAXBContext.newInstance(Holder.class, Bar.class, Baz.class); 

    Holder holder = new Holder(); 
    holder.addThing(new Bar("1")); 
    holder.addThing(new Baz(2)); 
    holder.addThing(new Baz(3)); 

    for (IFoo thing : holder.getThings()) { 
     thing.jump(); 
    } 

    StringWriter s = new StringWriter(); 
    context.createMarshaller().marshal(holder, s); 

    String data = s.toString(); 

    System.out.println(data); 

    StringReader t = new StringReader(data); 
    Holder holder2 = (Holder)context.createUnmarshaller().unmarshal(t); 

    for (IFoo thing : holder2.getThings()) { 
     thing.jump(); 
    } 
} 
catch (Exception e) { 
    System.err.println(e.getMessage()); 
} 

물론 간단한 예입니다. 요점은 Bar와 Baz라는 매우 다른 구현 클래스를 하나의 컬렉션에 저장해야한다는 것입니다. 글쎄, 나는 그것들이 꽤 비슷한 공용 인터페이스를 가지고 있다는 것을 관찰했다. 그래서 나는 IFoo 인터페이스를 만들고 그것을 구현하기 위해 두 가지 인터페이스를 만들었다. 이제이 컬렉션을 XML에 저장하고 XML에서로드하는 도구가 필요합니다. 불행히도,이 코드는 작동하지 않습니다. 컬렉션은 저장되었지만로드 할 수 없습니다! 의도 된 출력은

1 
2 
3 
some xml 
1 
2 
3 

그러나 불행하게도, 실제 출력이

1 
2 
3 
some xml 
com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to testapplication1.IFoo 

분명히, 나는 다른 방법으로 주석을 사용할 필요가이다? 아니면 JAXB를 포기하고 다른 것을 찾아야할까요? 나는 모든 클래스에 대해 "XMLNode toXML()"메서드를 작성할 수 있지만, 마샬링 할 수는 없지만 ...

+0

의 @XmlSeeAlso –

+0

가능한 복제의 사용 설명서를 확인 http://stackoverflow.com/questions/4144296/marshalling -a-list-of-objects-with-jaxb는 또한 인터페이스 유형 목록을 묻고 받아 들인 응답에서 다른 작동 방식을 사용합니다. –

답변

8

다음 코드를 시도해보십시오. @XmlAnyElement(lax=true). lax 플래그는 @XmlRootElement@XmlElementDecl 주석을 기반으로 요소를 도메인 객체와 일치하도록 JAXB (JSR-222) 구현에 알립니다. 그것 없이는 내용은 DOM 노드로 취급됩니다. 추가 정보

@XmlRootElement 
public class Holder { 
    private List<IFoo> things; 

    public Holder() { 
     things = new ArrayList<>(); 
    } 

    @XmlElementWrapper 
    @XmlAnyElement(lax=true) 
    public List<IFoo> getThings() { 
     return things; 
    } 

    public void addThing(IFoo thing) { 
     things.add(thing); 
    } 
} 

+6

그것은 작동합니다. 고맙습니다! 하지만이 JAXB의 모든 것들은 흑 마술과 같습니다. 아직 그것에 대한 이해할 수있는 가이드를 찾지 못했습니다. –

+1

@Joker_vD - 자바 XML 및 JSON 바인딩 블로그 (http://blog.bdoughan.com/) 및 EclipseLink JAXB (MOXy) 사용자 가이드 (http://wiki.eclipse.org/EclipseLink/UserGuide/MOXy)를 확인하십시오. –

+0

아래에 링크 된 이전 질문에 대한 대답에서 제공 한 접근 방식과 비교하여이 접근 방식의 장단점은 무엇입니까? 예를 들어 이전 답변에서는 구현 집합이 목록을 보유한 클래스에 알려져 있다고 가정합니다. http://stackoverflow.com/a/4145801/202009 –

관련 문제