1

下面(在这个问题的末尾)是一个使用 Java 泛型的通用 JAXB 编组器/解组器。有用。它可以用一行来编组/解组 JAXB 对象:

JAXBUtils jaxbUtils = new JAXBUtils(ObjectFactory.class);
SomeClass object = jaxbUtils.unmarshall("<some xml >...");
String xml  = jaxbUtils.marshall(object);

我还需要克隆其中一些对象,因此我使用 marshall 和 unmarshall 来深度克隆任何 JAXB 对象。这也可以在没有任何编译器错误的情况下工作(只是一些被注释抑制的警告)。

SomeClass object = ... some JAXB object obtained from XML
SomeClass cloneObject = clone(object);

但在另一个环境(持续集成)中,我在克隆方法返回行中遇到编译器错误:

type parameters of <T>T cannot be determined; no unique maximal instance exists for type variable T with upper bounds T,java.lang.Object

return unmarshal(marshal(object));
                ^

我将本地环境从 1.6.0_27 降级到 1.6.0_23,所以我在 CI 服务器中使用了完全相同的版本,因为我发现在这些版本之间修复了一些与通用代码相关的错误:

java 版本“1.6.0_23”Java(TM) SE 运行时环境(构建 1.6.0_23-b05)

但是代码仍然对我有用,没有编译器错误,单元测试通过,一切正常。

我尝试将克隆方法更改为:

public <T> T clone(T object) throws UnsupportedEncodingException, JAXBException {
    return this.<T>unmarshal(this.<T>marshal(object));
}

这也为我编译并看起来为编译器提供了更多提示,但我不确定它是否会解决服务器中的问题,因为我无法重现错误。

您认为在克隆方法中使用泛型代码有什么问题吗?它是编译器中的错误还是我的代码不正确?如果它不正确,为什么它对我有用!?

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;

import org.xml.sax.InputSource;

public class JAXBUtils {

    private Marshaller marshaller;
    private Unmarshaller unmarshaller;

    public JAXBUtils(Class... classesToBeBound) throws JAXBException {
        final JAXBContext context = JAXBContext.newInstance(classesToBeBound);
        unmarshaller = context.createUnmarshaller();
        marshaller = context.createMarshaller();
    }

    @SuppressWarnings("unchecked")
    public <T> String marshal(T object) throws UnsupportedEncodingException, JAXBException {
        return marshal(object, object.getClass().getSimpleName(), (Class<T>) object.getClass());
    }

    public <T> String marshal(T object, String name, Class<T> clazz) throws JAXBException {
        final JAXBElement<T> jaxbElement = new JAXBElement<T>(new QName(name), clazz, object);
        final OutputStream os = new ByteArrayOutputStream();
        marshaller.marshal(jaxbElement, os);
        return os.toString();
    }

    @SuppressWarnings("unchecked")
    public <T> T unmarshal(String xml) throws UnsupportedEncodingException, JAXBException {
        final InputSource is = new InputSource(new ByteArrayInputStream(xml.getBytes("utf-8")));
        final Object object = unmarshaller.unmarshal(is);
        // JAXB sometimes returns directly the object and sometimes wraps it in a JAXBElement.
        // Not sure why just handling both cases.
        return object instanceof JAXBElement ? ((JAXBElement<T>) object).getValue() : (T) object;
    }

    public <T> T clone(T object) throws UnsupportedEncodingException, JAXBException {
        return unmarshal(marshal(object));
    }

}

更新:它给出编译器错误的服务器是 RedHat Linux(5 或 6 不确定)。正如我所说的java版本是一样的,所以我猜这个bug是针对windows修复的,而不是针对linux的。我会尝试访问一些linux机器来尝试。

更新:代码在 debian/open-jdk 和 ubuntu/sun-jdk6u23 中编译没有任何错误或警告。我无法在 RedHat/sun-jdk6u23 上进行测试。

4

0 回答 0