2011-10-07 13 views
6

Đây là tình huống khó xử của tôi:Không thể Marshal java.lang.String

Tôi có một lớp dto cho marshaling qua lại từ/sang XML. Đây là mẹo: Vì số lượng các lớp dto mà dự án của chúng tôi đề cập đến là các bộ sưu tập với thẻ outter số nhiều, tôi quyết định tạo một bộ sưu tập ủy quyền cho phép tôi thực hiện một trong các lớp này và dễ dàng biến chúng thành một Bộ sưu tập và nhận được sự tiện lợi đi kèm với nó (lặp lại, thêm, v.v.).

Trong dự án của chúng tôi, chúng tôi có các thử nghiệm marshaling để loại bỏ các lỗi chú thích và như vậy. Dưới đây là mã sự cố của tôi.

Sự cố: Tùy thuộc vào trình so khớp, nếu tôi mở rộng QuickCollection này, tôi nhận được lỗi dưới đây. Khi đối tượng không bị so sánh với xml khi sử dụng CXF như một phản hồi cho yêu cầu webservice, nó không thành công. Lỗi chính xác: com.sun.istack.SAXException2: không thể sắp xếp thứ tự "java.lang.String" làm phần tử vì thiếu chú thích @XmlRootElement

Khi nó được sắp xếp/unmarshaled với JAXB trong thử nghiệm thì không sao. Khi cùng một QuickCollection này được sử dụng để sắp xếp lại kết quả từ bên thứ ba bằng cách sử dụng Spring RestOperations và hoạt động tốt

vít tâm: Khi tôi loại bỏ thừa kế và quản lý bộ sưu tập với tư cách thành viên riêng tư, tất cả chỉ hoạt động!

Điều này không tạo ra ý nghĩa với tôi khi tôi đang trả về kiểu dữ liệu chính xác trong cả hai trường hợp.

Dưới đây là tất cả các mã có liên quan.

Đây là lớp đại biểu được kế thừa.

public class QuickCollection<T> implements Collection<T> { 
    // to be set if needed after instantiation. To behave like a normal collection, we set it to something safe 
    protected Collection<T> delegate = Collections.emptySet(); 

    public QuickCollection() { 
    } 

    public QuickCollection(Collection<T> delegate) { 
     this.delegate = delegate; 
    } 

    @Override 
    public int size() { 
     return delegate.size(); 
    } 

    @Override 
    public boolean isEmpty() { 
     return delegate.isEmpty(); 
    } 

    @Override 
    public boolean contains(Object o) { 
     return delegate.contains(o); 
    } 

    @Override 
    public Iterator<T> iterator() { 
     return delegate.iterator(); 
    } 

    @Override 
    public Object[] toArray() { 
     return delegate.toArray(); 
    } 

    @Override 
    public <T> T[] toArray(T[] a) { 
     return delegate.toArray(a); 
    } 

    @Override 
    public boolean add(T t) { 
     return delegate.add(t); 
    } 

    @Override 
    public boolean remove(Object o) { 
     return delegate.remove(o); 
    } 

    @Override 
    public boolean containsAll(Collection<?> c) { 
     return delegate.containsAll(c); 
    } 

    @Override 
    public boolean addAll(Collection<? extends T> c) { 
     return delegate.addAll(c); 
    } 

    @Override 
    public boolean removeAll(Collection<?> c) { 
     return delegate.removeAll(c); 
    } 

    @Override 
    public boolean retainAll(Collection<?> c) { 
     return delegate.retainAll(c); 
    } 

    @Override 
    public void clear() { 
     delegate.clear(); 
    } 

    @Override 
    public String toString() { 
     return "" + delegate.toString(); 
    } 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 

     QuickCollection that = (QuickCollection) o; 

     if (delegate != null ? !delegate.equals(that.delegate) : that.delegate != null) return false; 

     return true; 
    } 

    @Override 
    public int hashCode() { 
     return delegate != null ? delegate.hashCode() : 0; 
    } 
} 

Đây là con DTO lớp

@XmlAccessorType(XmlAccessType.PROPERTY) 
@XmlType(name = "BuddyCodes") 
@XmlRootElement(name = "BuddyCodes") 
public class BuddyCodes extends QuickCollection<String> implements Xml { 

    private Long accountId; 

    private Date expirationDate; 

    public BuddyCodes() { 
     super.delegate = new HashSet<String>(); 
    } 

    public BuddyCodes(Long accountId, Set<String> codes, Date expirationDate) { 
     super(codes); 
     this.accountId = accountId; 
     this.expirationDate = expirationDate; 
     super.delegate = new HashSet<String>(); 

    } 

    public BuddyCodes(Long accountId, Date expirationDate) { 
     this.accountId = accountId; 
     this.expirationDate = expirationDate; 
     super.delegate = new HashSet<String>(); 
    } 

    @Override 
    public String toXml() { 
     String retVal; 
     try { 
      retVal = StringUtils.toXml(this); 
     } 
     catch (JAXBException e) { 
      retVal = e.toString(); 
     } 
     return retVal; 

    } 

    public Long getAccountId() { 
     return accountId; 
    } 

    public void setAccountId(Long accountId) { 
     this.accountId = accountId; 
    } 

    public Set<String> getCodes() { 
     return (Set<String>) super.delegate; 
    } 

    @XmlElement(name = "code") 
    public void setCodes(Set<String> codes) { 
     super.delegate = codes; 
    } 

    public Date getExpirationDate() { 
     return expirationDate; 
    } 

    public void setExpirationDate(Date expirationDate) { 
     this.expirationDate = expirationDate; 
    } 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 

     BuddyCodes that = (BuddyCodes) o; 

     if (accountId != null ? !accountId.equals(that.accountId) : that.accountId != null) return false; 
     if (delegate != null ? !super.delegate.equals(that.delegate) : that.delegate != null) return false; 
     if (expirationDate != null ? !expirationDate.equals(that.expirationDate) : that.expirationDate != null) 
      return false; 

     return true; 
    } 

    @Override 
    public int hashCode() { 
     int result = accountId != null ? accountId.hashCode() : 0; 
     result = 31 * result + (expirationDate != null ? expirationDate.hashCode() : 0); 
     result = 31 * result + (super.delegate != null ? super.delegate.hashCode() : 0); 
     return result; 
    } 

    @Override 
    public String toString() { 
     return "BuddyCodes{" + 
       "accountId=" + accountId + 
       "codes=" + super.delegate + 
       ", expirationDate=" + expirationDate + 
       '}'; 
    } 
} 

Và nó không hoạt động. Tôi gặp lỗi.

Bây giờ, đây là lớp con sau khi loại bỏ thừa kế và nó hoạt động !!!

import javax.xml.bind.JAXBException; 
import javax.xml.bind.annotation.*; 
import java.util.Collection; 
import java.util.Date; 
import java.util.HashSet; 
import java.util.Set; 

/** 
* @author christian.bongiorno 
*   Date: 10/3/11 
*   Time: 6:11 PM 
*/ 
@XmlAccessorType(XmlAccessType.PROPERTY) 
@XmlType(name = "BuddyCodes") 
@XmlRootElement(name = "BuddyCodes") 
public class BuddyCodes implements Xml { 

    private Long accountId; 

    private Date expirationDate; 
    private Set<String> delegate; 
    public BuddyCodes() { 
     delegate = new HashSet<String>(); 
    } 

    public BuddyCodes(Long accountId, Set<String> codes, Date expirationDate) { 
     this.accountId = accountId; 
     this.expirationDate = expirationDate; 
     delegate = new HashSet<String>(); 

    } 

    public BuddyCodes(Long accountId, Date expirationDate) { 
     this.accountId = accountId; 
     this.expirationDate = expirationDate; 
     delegate = new HashSet<String>(); 
    } 

    @Override 
    public String toXml() { 
     String retVal; 
     try { 
      retVal = StringUtils.toXml(this); 
     } 
     catch (JAXBException e) { 
      retVal = e.toString(); 
     } 
     return retVal; 

    } 

    public Long getAccountId() { 
     return accountId; 
    } 

    public void setAccountId(Long accountId) { 
     this.accountId = accountId; 
    } 

    public Set<String> getCodes() { 
     return delegate; 
    } 

    @XmlElement(name = "code") 
    public void setCodes(Set<String> codes) { 
     delegate = codes; 
    } 

    public Date getExpirationDate() { 
     return expirationDate; 
    } 

    public void setExpirationDate(Date expirationDate) { 
     this.expirationDate = expirationDate; 
    } 

    public boolean add(String s) { 
     return delegate.add(s); 
    } 

    public int size() { 
     return delegate.size(); 
    } 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 

     BuddyCodes that = (BuddyCodes) o; 

     if (accountId != null ? !accountId.equals(that.accountId) : that.accountId != null) return false; 
     if (delegate != null ? !delegate.equals(that.delegate) : that.delegate != null) return false; 
     if (expirationDate != null ? !expirationDate.equals(that.expirationDate) : that.expirationDate != null) 
      return false; 

     return true; 
    } 

    @Override 
    public int hashCode() { 
     int result = accountId != null ? accountId.hashCode() : 0; 
     result = 31 * result + (expirationDate != null ? expirationDate.hashCode() : 0); 
     result = 31 * result + (delegate != null ? delegate.hashCode() : 0); 
     return result; 
    } 


} 

Tại sao vấn đề kế thừa?

Tôi chưa tìm ra điều này nhưng tôi có một DTO khác trong bố cục tương tự (BuddyTypes BuddyType). BuddyType có 2 thành viên: Long và String. Cả hai đều được chú thích là XmlElement. Điều này hoạt động tốt.

Có vẻ như vấn đề là các thành viên của nhóm thiết lập đại biểu không được chú thích trong trường hợp sự cố của tôi và tôi không biết cách chú giải thành viên chính. Là một lớp kế thừa, sẽ không có ý nghĩa gì nếu có một số loại tên/chú thích mặc định. Nhưng, tôi đã thử sự điên rồ này và chú thích bị bỏ qua - Tôi đã thấy các chú thích thành viên của phụ huynh bị bỏ qua trước đây vì vậy đây không phải là mới.

Tôi không biết nếu có thể, nhưng tôi cần chú thích một thành viên chính.

+1

Bạn đã thấy chú thích 'XmlElementWrapper' chưa? Nếu tôi hiểu yêu cầu của bạn một cách chính xác, đó sẽ là một cách đơn giản hơn nhiều để thêm phần tử bao bọc số nhiều. –

+0

Tôi đã thấy nó, nhưng tất cả những gì tôi từng thấy là "BlahBlahWrapper" khi nó được sử dụng. Nó mua gì cho tôi? Tôi sẽ nhìn vào nó –

Trả lời

3

Một chút ra khỏi hộp: hãy thử Simple XML thư viện thay vì JAXB. Kinh nghiệm của tôi với nó là tốt nhất.