【问题标题】:Jersey Jackson unmarshall JSON泽西杰克逊解组 JSON
【发布时间】:2016-08-30 17:12:20
【问题描述】:

我正在开发一个嵌入式 jersey 实例,它将运行 JAXB RESTful 服务。我已经通过两个步骤配置了 Jackson:

  1. 将此添加到我的 POM

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>2.23.2</version>
    </dependency>
    
  2. 在我的应用程序中注册它

    public HandheldApplication() {
    scripts.add(HandheldServer.class);
    scripts.add(BasicScript.class);
    // Add JacksonFeature.
    scripts.add(JacksonFeature.class);
    scripts.add(LoggingFilter.class);
    

    }

我有一个复杂的对象来回传递,如下所示:

package com.ziath.handheldserver.valueobjects;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.*;

@SuppressWarnings("restriction")
@XmlRootElement
public class Widget {

private String key;
private String name;
private List<String> options = new ArrayList<String>();
private String value;
private String type;

public Widget(){
    super();
}

public Widget(String key, String name, List<String> options, String value,
        String type) {
    super();
    this.key = key;
    this.name = name;
    this.options = options;
    this.value = value;
    this.type = type;
}

public String getKey() {
    return key;
}
public void setKey(String key) {
    this.key = key;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public List<String> getOptions() {
    return options;
}
public void setOptions(List<String> options) {
    this.options = options;
}
public String getValue() {
    return value;
}
public void setValue(String value) {
    this.value = value;
}
public String getType() {
    return type;
}
public void setType(String type) {
    this.type = type;
}

}

当我在如下所示的 GET 方法中执行此操作时:

@Override
@GET
@Path("getKeys")
@Produces(MediaType.APPLICATION_JSON)
public List<Widget> getKeys(@QueryParam(value = "page") int page) 

这很好,我得到了 JSON;但是,当我执行它时,它是一个 PUT,如下所示:

@Override
@PUT
@Path("validateKeys")
@Produces({MediaType.APPLICATION_JSON})
@Consumes(MediaType.APPLICATION_JSON)
public boolean validateKeys(@QueryParam(value = "page")int page, @QueryParam(value = "widgets")List<Widget> widgets) 

当我执行 PUT 以访问此方法时,我得到如下堆栈跟踪:

Caused by: org.glassfish.jersey.internal.inject.ExtractorException: Error un-marshalling JAXB object of type: class com.ziath.handheldserver.valueobjects.Widget.
    at org.glassfish.jersey.jaxb.internal.JaxbStringReaderProvider$RootElementProvider$1.fromString(JaxbStringReaderProvider.java:195)
    at org.glassfish.jersey.server.internal.inject.AbstractParamValueExtractor.convert(AbstractParamValueExtractor.java:139)
    at org.glassfish.jersey.server.internal.inject.AbstractParamValueExtractor.fromString(AbstractParamValueExtractor.java:130)
    at org.glassfish.jersey.server.internal.inject.CollectionExtractor.extract(CollectionExtractor.java:88)
    at org.glassfish.jersey.server.internal.inject.CollectionExtractor$ListValueOf.extract(CollectionExtractor.java:107)
    at org.glassfish.jersey.server.internal.inject.QueryParamValueFactoryProvider$QueryParamValueFactory.provide(QueryParamValueFactoryProvider.java:89)
    ... 38 more
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:563)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:249)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:140)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:123)
    at org.glassfish.jersey.jaxb.internal.JaxbStringReaderProvider$RootElementProvider$1.fromString(JaxbStringReaderProvider.java:190)
    ... 43 more

所以在我看来,Jackson 正确地将我的 POJO编组到 JSON 中,但试图将其解组为 XML。请注意,我从 MOXy 转到 Jackson 是因为我需要能够处理来回的收藏,而 MOXy 显然无法做到这一点。

我是否错过了告诉 Jackson/Jersey 双向使用 JSON 的设置?

【问题讨论】:

  • 你是如何执行 PUT 的?来自 javascript、命令行、JAX-RS 客户端或其他什么?
  • 对不起;我发现问题的答案是 Jackson/Jersey 自动将 POJO 编组为 JSON,但没有解组,因此我需要删除顶部的 XML 相关注释并手动放入 fromString 方法以将 JSON 解组到对象中。
  • 泽西当然也可以从身体中解组实体。我怀疑您在发出请求时没有提供正确的 Content-Type 标头(应用程序/json),这就是为什么我想知道您是如何调用它的(当我从命令行 curl 时,我经常忘记 @987654328 @)。
  • 您好 - 没有问题是我需要为对象提供解组方法 - 请参阅我自己的答案。提供了正确的内容类型,但如果没有辅助方法,它无法自动解组 JSON - 辅助方法 fromString 由 Jersey/Jackson 寻求,并且一切正常。现在我提供了 unmarshall 方法,它工作得很好。感谢您抽出宝贵时间发表评论。
  • 我怀疑你可以在没有静态 fromString 方法和没有@FormParam 的情况下完成它。但听起来您的解决方案适合您!

标签: json jersey jackson jax-rs


【解决方案1】:

尝试删除@QueryParam(value = "widgets"),因为您应该将其作为实体主体传递 - 而不是查询参数。

@PUT
@Path("validateKeys")
@Produces({MediaType.APPLICATION_JSON})
@Consumes(MediaType.APPLICATION_JSON)
public boolean validateKeys(@QueryParam(value = "page")int page, List<Widget> widgets) 

你也可以制作包装类:

@XmlRootElement
public class Widgets {

    private List<Widget> widgets; 

    // other fields, setters and getters
}

然后:

@PUT
@Path("validateKeys")
@Produces({MediaType.APPLICATION_JSON})
@Consumes(MediaType.APPLICATION_JSON)
public boolean validateKeys(@QueryParam(value = "page")int page, Widgets widgets) 

我建议阅读一些关于 REST 设计的讨论,因为您在路径中使用动词:

【讨论】:

  • 感谢我在上面发布了答案并感谢 REST 语法;我首先自动生成了代码存根,稍后我将在部署时对其进行清理。
【解决方案2】:

我在 QueryParam 和 FormParam 之间切换,试图让其中一个工作。如果我使用 FormParam,我还需要将消耗更改为 APPLICATION_FORM_URLENCODED。

实际的问题是 Jackson 的默认解组是使用 XML,因为它被标记为 XML 资源 - 把它拿出来!我终于设法通过使用静态 fromString 方法从 JSON 中解组。然后处理列表;我不能使用包装器类,因为这需要高度跨语言,并且使用列表公开包装器会使 Python、C# 等的实现变得复杂。让它接受带有包装器的列表的方法是发布名称参数(在本例中为小部件)多次。然后每个传入的 JSON 都会被 fromString 方法调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-19
    • 2012-06-07
    • 2013-03-02
    • 1970-01-01
    相关资源
    最近更新 更多