无法序列化java.lang.String

6

这是我的困境:

我有一个DTO类用于在XML之间进行编组和解组。

问题在于:由于我们的项目处理包含复数外部标记的DTO类的数量很多,我决定创建一个委托集合,让我可以将其中一个类轻松地转换为集合,并获得方便的功能(迭代、添加等)。

在我们的项目中,我们进行了编组测试以排除注释错误等。以下是我的麻烦代码:

问题: 根据编组程序,如果我扩展此QuickCollection,则会出现下面的错误。 当使用CXF作为对Web服务请求的响应来解组对象为XML时,它会失败。具体的错误信息如下: com.sun.istack.SAXException2: unable to marshal type "java.lang.String" as an element because it is missing an @XmlRootElement annotation

在测试中使用JAXB进行编组/解组时,一切正常。 当使用相同的QuickCollection将结果从第三方编组并进行编组时,使用Spring RestOperations也可以正常工作。

混乱的想法是: 当我删除继承并将集合管理为私有成员时,所有内容都正常工作!

对我来说,这毫无意义,因为在两种情况下我都实际返回了确切的数据类型。

以下是所有相关代码。

这是继承的委托类。

    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;
    }
}

这是子DTO类。
@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 +
                '}';
    }
}

它不起作用。我收到了错误信息。

现在,这是删除继承后的子类,它可以工作!!!

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;
    }


}

为什么继承很重要?
我还没有想通,但是我有另一个类似的DTO(BuddyTypes BuddyType)布局。BuddyType有两个成员:Long和String。两者都被注释为XmlElement。这个可以正常工作。
看起来问题出在我的问题案例中,构成委托的集合成员没有注释,我不知道如何注释父成员。作为一个继承类,拥有某种默认名称/注释是没有意义的。但是,我尝试了这种疯狂的方法,注释被忽略了 - 我以前见过父成员注释被忽略,所以这并不新鲜。
我不知道是否可能,但我需要注释一个父成员。

1
你看过XmlElementWrapper注解吗?如果我正确理解你的需求,那将是一种更简单的方式来添加一个复数的包装元素。 - Jörn Horstmann
我看过它,但我所看到的只有在使用时出现的“BlahBlahWrapper”。它能给我带来什么好处?我会研究一下。 - Christian Bongiorno
1个回答

3
有点不寻常:尝试使用Simple XML库而不是JAXB。我的经验是最好的。请查看Simple XML库。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接