【问题标题】:Expected an array of objects but got an object in an object需要一个对象数组,但在一个对象中得到了一个对象
【发布时间】:2015-11-12 21:25:45
【问题描述】:

在我目前正在进行的一个项目中,我遇到了一个角度异常:Error: [$resource:badcfg] Error in resource configuration. Expected response to contain an array but got an object?

在寻找解决方案的过程中,我直接在浏览器中输入了 Web 服务的 URL,但令人惊讶的是,我没有收到预期的数组。

网络服务类:

@Path("/menu")
public class MenuHandler {
    @GET
    @Path("/cls")
    @Produces(MediaType.APPLICATION_JSON)
    public List<Clazz> getCLSs()    {
        Clazz clazz = new Clazz();
        Clazz.setFoo("foo");
        Clazz.setBar("bar");

        ArrayList<Clazz> clazzes = new ArrayList<>();
        clazzes.add(clazz);

        return clazzes;
    }
}

当我输入 URL http://localhost:8080/myProject/rest/menu/cls 时,我希望看到一个带有 JSON 对象的 JSON 数组:

[ {"foo": "foo", "bar": "bar"} ]

但相反,我收到一个 JSON 对象,该对象具有我期望的 JSON 对象的属性,但没有任何数组:

{
  "clazz": {
    "foo": "foo",
    "bar": "bar"
  }
}

所以我想知道为什么没有数组以及当我添加另一个 Clazz 对象时会发生什么。在这种情况下,我仍然得到一个 JSON 对象,但这次参数之一是我希望从一开始就拥有的 JSON 数组。

{
  "clazz": [
    {
      "foo": "foo",
      "bar": "bar"
    },
    {
      "foo": "foo2",
      "bar": "bar2"
    }
  ]
}

谁能解释一下为什么会发生这种行为以及我的想法哪里出错了?

【问题讨论】:

  • 请显示您使用的 JSON 提供程序、与 JSON 相关的所有依赖项以及您可能感兴趣的任何 JSON 配置。这似乎是一个配置问题。显式配置或可配置的默认配置(并且可能是固定的)。
  • @peeskillet javax.json-api 和 jersey-json-1.17.1 jar 都在这个项目的类路径中。知道如何找出实际使用的是哪一个吗?
  • 我删除了他的 javax.json-api,一切似乎都正常。不幸的是,这并没有解决问题。在另一个项目中,也使用了 jersey-json 并且一切都按预期工作。我试图寻找差异,但我正在查看它。
  • 查看 jersey-json 是否被使用的一种方法是创建一个ContextResolver&lt;ObjectMapper&gt;。在getContext 中添加打印语句。 jersey-json 使用杰克逊。如果它被使用,getContext 方法将被调用。如果它没有被调用,那么它就没有被使用。在这种情况下,您可能想尝试在序列化/反序列化上触发一些异常,以尝试从序列化程序获取堆栈跟踪,以查看实际使用的序列化程序。
  • 不太确定你的想法,所以我在被调用方法中创建了一个匿名类,并在 applicationContext.xml 中创建了一个单独的类。没有调用任何打印语句。不过球衣好像还是用了at com.sun.jersey.json.impl.provider.entity.JSONListElementProvider.writeList(JSONListElementProvider.java:145) at com.sun.jersey.core.provider.jaxb.AbstractListElementProvider.writeTo(AbstractListElementProvider.java:264) at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:306) at com.sun.jersey.server.impl.appl...

标签: java json jersey tomcat8


【解决方案1】:

您可能想使用 GenericEntity 并返回 Response。

@GET
@Path("/cls")
@Produces({ MediaType.APPLICATION_JSON })
public Response getCLSs() {
    List<Clazz> objects = new ArrayList<Clazz>();
     // logic goes here

     // now wrap List into GenericEntity 
    GenericEntity<List<Clazz>> entity = new GenericEntity<List<Clazz>>(
            objects) {
    };
    return Response.ok(entity).build();
}

【讨论】:

  • 感谢您与我一起思考。不幸的是,这并没有改变我从服务器收到的响应
【解决方案2】:

所以我发现了问题。我能够重现它。看来您只是忘记启用 POJOMappingFeature

<init-param>
    <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
    <param-value>true</param-value>
</init-param>

这使用 Jackson 来反序列化/序列化。如果未设置,它将使用 Jersey 的内部 JSON 提供程序来反序列化/序列化。我不确定如何配置默认提供程序,但我认为还是使用 Jackson 更安全。


除此之外,在我上面的 cmets 中,我说要测试是否使用了 Jackson。轻松完成此操作的一种方法是创建一个ContextResolver 和一个 s.o.p.在getContext 方法中。当需要映射器时调用此方法。因此,如果正在使用 Jackson,则应该打印 s.o.p

@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {

    private final ObjectMapper defaultMapper;

    public ObjectMapperContextResolver() {
        defaultMapper = new ObjectMapper();
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        System.out.println("--- getContext ---");
        return defaultMapper;
    }  
}

请注意,这也是使用 Jackson 序列化/反序列化进行任何配置的一种方式(只需配置映射器)。

【讨论】:

  • 谢谢!我还不是很清楚发生了什么,但是我会在这个书签上添加书签,并在我达到我的最后期限时返回它:) 作为奖励,这个 getContext 方法确实被执行了。使用的 Json 提供程序是 org.codehaus.jackson.jaxrs.JacksonJsonProvider
  • 是的,我没有意识到泽西岛有自己的内部供应商。在我看到你的 cmets 中的堆栈跟踪之前,从来没有真正看过这个罐子。所以我想我的评论应该是“检查是否使用了Jackson”,而不是“检查是否使用了jersey-json”。我们生活,我们学习:-)
猜你喜欢
  • 1970-01-01
  • 2019-12-23
  • 2015-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-13
  • 1970-01-01
  • 2012-06-07
相关资源
最近更新 更多