【问题标题】:Consuming JSON with Jersey 2.3 throws XML exception使用 Jersey 2.3 使用 JSON 会引发 XML 异常
【发布时间】:2013-10-19 17:40:56
【问题描述】:

我正在尝试让 Jersey 2.3 + Moxy 与我的自定义对象一起工作。当我从这些对象生成 JSON 时一切正常,但是当我想通过 POST 使用它们时拒绝工作。代码优先:

自定义对象:

@XmlRootElement
public class ContentAction extends Action {

    private String contentType;
    private Integer contentLength;

    public ContentAction() {
        setType(ActionType.CONTENT);
    }

    public String getContentType() {
        return contentType;
    }

    public void setContentType(String contentType) {
        this.contentType = contentType;
    }

    public Integer getContentLength() {
        return contentLength;
    }

    public void setContentLength(Integer contentLength) {
        this.contentLength = contentLength;
    }
}

资源片段(路径在类上声明):

@POST
@Produces(JsonHelper.JSON_UTF8)
public Action saveAction(@QueryParam("action") ContentAction action) throws IOException {
    ActionEntity entity = actionConverter.toEntity(action);
    entity.setBeacon(beaconService.findById(action.getBeacon().getId()));

    return actionConverter.convert(actionService.save(entity));
}

API 调用者(负责发送请求的类):

URI uri = buildUri(path, params);

HttpPost httpPost = new HttpPost(uri);
httpClient.execute(httpPost);

buildUri 只是从地址和参数创建 URI 操作转换为 JSON 如下:mapper.writeValueAsString(action)

还有例外:

org.glassfish.jersey.server.internal.inject.ExtractorException: Error unmarshalling JAXB object of type "class com.kontakt.platform.apicommon.model.ContentAction".
    at org.glassfish.jersey.server.internal.inject.JaxbStringReaderProvider$RootElementProvider$1.fromString(JaxbStringReaderProvider.java:195)
    at org.glassfish.jersey.server.internal.inject.AbstractParamValueExtractor.convert(AbstractParamValueExtractor.java:138)
    at org.glassfish.jersey.server.internal.inject.AbstractParamValueExtractor.fromString(AbstractParamValueExtractor.java:129)
    at org.glassfish.jersey.server.internal.inject.SingleValueExtractor.extract(SingleValueExtractor.java:83)
    at org.glassfish.jersey.server.internal.inject.QueryParamValueFactoryProvider$QueryParamValueFactory.provide(QueryParamValueFactoryProvider.java:88)
    at org.glassfish.jersey.server.spi.internal.ParameterValueHelper.getParameterValues(ParameterValueHelper.java:81)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$AbstractMethodParamInvoker.getParamValues(JavaResourceMethodDispatcherProvider.java:121)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:195)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:104)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:353)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:343)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
    at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:255)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:318)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:235)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:983)
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:359)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:372)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:218)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1008)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:1852)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:722)
Caused by: javax.xml.bind.UnmarshalException
 - with linked exception:
[org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.]
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:335)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:512)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:209)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:175)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:140)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:123)
    at org.glassfish.jersey.server.internal.inject.JaxbStringReaderProvider$RootElementProvider$1.fromString(JaxbStringReaderProvider.java:190)
    ... 40 more
Caused by: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:177)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:441)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:368)
    at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1388)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:998)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:607)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:116)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:489)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:835)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:764)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:123)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1210)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:568)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:203)
    ... 44 more

当我删除 @XmlRootElement 时,Jersey 尝试使用字符串参数(如果添加)从构造函数创建对象 = 不自动创建 bean。

我已经被这个问题困扰了两天,如果能提供任何帮助,我将不胜感激。

【问题讨论】:

  • JsonHelper.JSON_UTF8对应什么?在基于异常的当前配置中,使用的是 JAXB 参考实现而不是 MOXy,它正在尝试将输入作为 XML 处理。
  • 查询参数action怎么样?你在那里发送 XML 吗?

标签: json jersey entity moxy


【解决方案1】:

我认为问题在于您需要设置内容类型。由于您没有指定内容类型,因此 jersey 假设它正在接收 xml,但实际上是 json。错误消息来自 jaxb 尝试读取 xml 标头并查找无效字符。尝试使用 jersey 客户端而不是 http 帖子。此外,我认为您可能会更改您的 @Produces(MediaType.APPLICATION_JSON) 以保持一致性。

@Produces(MediaType.APPLICATION_JSON)

POST 代码示例

最重要的部分是我正在设置我要发布的类型(type(MediaType.Application_JSON)。

WebResource webResource = createRestClient(true).resource(
             REST_BASE_PATH + "/service");

ClientResponse response = webResource.type(MediaType.APPLICATION_JSON)
            .accept(MediaType.APPLICATION_JSON)
            .post(ClientResponse.class, contentActionObject);

Assert.assertTrue(response.getStatus() == 200);

如果您确实需要使用 HttpPost 对象,那么应该有一个配置选项来设置 http 标头。我已经使用 HttpUrlConnection 完成了这项工作。您必须将内容类型设置为 application/json 而不是 xml。

HttpURLConnection connection = null;
connection = (HttpURLConnection) new URL(requestUrl).openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/xml");
connection.setRequestProperty("Content-Type", "application/xml");

【讨论】:

  • 我已经在使用 Jersey 的客户端上更改了我的客户端实现(我使用的是 2.3.1 api,而不是您展示的 1.x),不幸的是它没有帮助。您还有其他想法吗?
  • 您收到的错误消息是因为 Jersey 正在接收 json 并期待 xml。SAXParse 异常是在尝试读取 标头时引起的。您是否尝试将@Consumes 更改为使用@Consumes(MediaType.APPLICATION_JSON)?并验证您是否将帖子设置为使用相同的 MediaType.APPLICATION_JSON 常量。 JsonHelper.JSON_UTF8 解析为什么?如果不是“application/json”那么你可能会遇到问题。
【解决方案2】:

EclipseLink MOXy 将被 Jersey 选为 JSON 绑定提供者,用于遵循以下模式的媒体类型。

  • */json(即 application/json 和 text/json)
  • /+json

根据您的例外情况,似乎用JsonHelper.JSON_UTF8 表示的媒体类型与此模式不匹配。

【讨论】:

  • JsonHelper.JSON_UTF8 仅设置为我没有问题的生产。但是,JSON_UTF8 与模式匹配 - 它是 MediaType.APPLICATION_JSON,最后带有地址 utf-8
【解决方案3】:

我知道这有点老了,但我在使用 Jersey 2.3 + Moxy 时遇到了基本相同的问题。相同的场景和相同的异常正在发生。唯一的区别是我的 POST 方法注释为:

@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)

我确实发现,当我在请求正文中传递相同的 JSON 表示而不是作为查询参数时,它被成功解组。这需要将您的 POST 方法声明更改为:

public Action saveAction(ContentAction action)

不确定这是否适合您。如果你找到了一个解决方案,我很想听听它是什么。

【讨论】:

    猜你喜欢
    • 2017-11-14
    • 2015-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多