javax.xml.bind.MarshalException - 链接异常 : [javax. xml.bind.JAXBException: class ** 其父类(super class)在此上下文中不为人所知

标签 java web-services jaxb

我有一个通用的 Web 服务,它需要一个 WebServiceRequest 对象。该对象具有 Object 类型的有效负载。以下是我的有效载荷的类型。

<xs:complexType name="payload">
    <xs:sequence>
        <xs:any processContents="lax"></xs:any>
    </xs:sequence>
</xs:complexType>

我为 Web 服务输入和输出类型创建了 JAXB 类。因此对于有效载荷,这是生成的字段。

 @XmlAnyElement(lax = true)
 private Object any;

下面是我的 JAXB 生成的 WebServiceRequest VO 的结构。

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "serviceRequest", namespace = "http://ws.test.svc.com/", propOrder = {
    "payload"
})
public class WebServiceRequest{
        @XmlElement
        private Payload payload;
} 

public class Payload{
 @XmlAnyElement(lax = true)
 private Object any;
}

我有一些自定义 POJO,我需要将其填充并设置为负载。我使用以下注释对这些 POJO 进行了注释

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class AddressVO {
    @XmlElement
    private String pinCode;
    @XmlElement
    private String city;
}

我为这个 POJO 填充了数据并尝试设置为 WebServiceRequest 的负载。但是当我这样做时,我遇到了以下异常。

javax.xml.bind.MarshalException
 - with linked exception:
[javax.xml.bind.JAXBException: class com.vo.test.AddressVO nor any of its super class is known to this context.

您能否提出一些克服此问题的方法?一合link有人提到它包含 @XmlSeeAlso,但我不能这样做,因为我的有效负载非常通用。请在这方面帮助我。

最佳答案

如果您不能应用 @XMLSeeAlso 注释,您将需要创建一个自定义的 MessageBodyReaderMessageBodyWriter 来负责在 Java 和 XML 之间编码和解码。下面显示了通用 MessageBodyReader 的抽象实现,它实际上旨在执行特定于类型的 XML 验证。作者比较相似,就不加了。

public abstract class AbstractXmlValidationReader<T> implements
        MessageBodyReader<T> {

    private final Providers providers;
    private final Schema schema;

    public AbstractXmlValidationReader(final Providers providers,
            final ServletContext servletContext, final String xsdFileName) {
        this.providers = providers;

        try {
            SchemaFactory sf = SchemaFactory
                    .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            File xsd = new File(servletContext.getRealPath(xsdFileName));
            schema = sf.newSchema(xsd);
        } catch (Exception e) {
            throw new RuntimeException(
                    "Unable to create XSD validation schema", e);
        }
    }

    @Override
    public boolean isReadable(Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {

        @SuppressWarnings("unchecked")
        Class<T> readableClass = (Class<T>) ((ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0];

        if (type == readableClass
                && type.isAnnotationPresent(XmlRootElement.class)) {
            return true;
        }
        return false;
    }

    @Override
    public T readFrom(Class<T> type, Type genericType,
            Annotation[] annotations, MediaType mediaType,
            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
            throws IOException, WebApplicationException {

        try {
            JAXBContext jaxbContext = null;
            ContextResolver<JAXBContext> resolver = providers
                    .getContextResolver(JAXBContext.class, mediaType);
            if (null != resolver) {
                jaxbContext = resolver.getContext(type);
            }
            if (null == jaxbContext) {
                jaxbContext = JAXBContext.newInstance(type);
            }
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            unmarshaller.setSchema(schema);

            @SuppressWarnings("unchecked")
            T entity = (T) unmarshaller.unmarshal(entityStream);
            return entity;
        } catch (JAXBException e) {
            throw new MessageBodyReaderValidationException(
                    "Failure while performing xml validation or xml marhalling!",
                    e);
        }
    }
} 

以及 Address 类型的具体实现

@Provider
@Consumes(MediaType.APPLICATION_XML)
public class AddressXmlValidationReader extends
        AbstractXmlValidationReader<Address> {

    private final static String xsdFileName = "/xsd/Address.xsd";

    public AddressXmlValidationReader(@Context Providers providers,
            @Context ServletContext servletContext) {
        super(providers, servletContext, xsdFileName);
    }
}

您现在需要的是对 MessageBodyReaderreadFrom 方法进行轻微修改,如下所示。对于 MessageBodyWriter,该方法称为 writeTo

@Override
public T readFrom(Class<T> type, Type genericType,
        Annotation[] annotations, MediaType mediaType,
        MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
        throws IOException, WebApplicationException {

    try {
        JAXBContext jaxbContext = null;
        ContextResolver<JAXBContext> resolver = providers
                .getContextResolver(JAXBContext.class, mediaType);

        if(entityStream != null){
            // TODO read the entityStream and determine the concrete type of the XML content
            type = ... ;
        }

        if (null != resolver) {
            jaxbContext = resolver.getContext(type);
        }
        if (null == jaxbContext) {
            jaxbContext = JAXBContext.newInstance(type);
        }
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        unmarshaller.setSchema(schema);

        @SuppressWarnings("unchecked")
        T entity = (T) unmarshaller.unmarshal(entityStream);
        return entity;
    } catch (JAXBException e) {
        throw new MessageBodyReaderValidationException(
                "Failure while performing xml validation or xml marhalling!",
                e);
    }
}

使用这种方法,您可以通过 Reader 和 Writer 实例的具体子类定义通用类型。一个可能的更具体的类型可以在抽象基类中确定(就像在这个例子中)或者它是从其他地方注入(inject)的。当然,您可以修改此 MessageBodyReader,以便在某处或其他地方确定 XML 输入的具体类型。但总的来说,这就是您解决问题的方式。


注意:

不要忘记在 Web 服务 Application 类中注册具体的 Reader 和 writer 实现。

@ApplicationPath("/services")
public class WSApplication extends Application {
    private Set<Object> singletons = new HashSet<Object>();
    private Set<Class<?>> classes = new HashSet<Class<?>>();
    public WSApplication() {
        ...
        classes.add(AddressXmlValidationReader.class);
        ...
    }
    ...
}

关于javax.xml.bind.MarshalException - 链接异常 : [javax. xml.bind.JAXBException: class ** 其父类(super class)在此上下文中不为人所知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20686351/

相关文章:

java - DateTimeFormatter 无法解析日期字符串,但 SimpleDateFormat 可以

java - 无法让我的代码在另一个图像的尺寸内生成图像。使用 LibGDX

java - Android:BitmapFactory.decodeStream() 在第一次成功后返回 null

java - 解码 soap 类转换异常

c# - 无法在 C# 中登录我的 netsuite 帐户

java - Solr,如何在 schema.xml 中定义嵌套文档

web-services - 如何使用 POSTMAN 测试 wcf soap 服务?

maven - 具有外部 XSD 依赖项的 jaxb2-maven-plugin

java - 没有 URI javax.xml.bind.UnmarshalException : unexpected element (uri :"", 本地 :"SearchAndList")。预期元素是(无)

JAXB - ClassNotFoundException : com. sun.xml.bind.ContextFactory_1_0_1