Expected an array of objects but got an object in an object

断了今生、忘了曾经 提交于 2019-11-26 18:36:07

问题


In a project I'm currently working on I got an angular exception: Error: [$resource:badcfg] Error in resource configuration. Expected response to contain an array but got an object?

In my search to find a solution I entered the URL of the web service directly into my browser and surprisingly I did not receive an array as expected.

The web service class:

@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;
    }
}

When I enter the url http://localhost:8080/myProject/rest/menu/cls I would expect to see a JSON array with JSON objects:

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

but instead, I receive an JSON object with a property the JSON object I was expecting without any array:

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

So I wondered why there was no array and what would happen when I add another Clazz object. In that case I still get a JSON object but this time one of the parameters is the JSON array that I would expect to have from the start.

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

Can somebody explain me why this behavior is happening and where my thinking went wrong?


回答1:


So I spotted the problem. I was able to reproduce it. It seems you just forgot the enable the POJOMappingFeature

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

This uses Jackson to deserialize/serialize. If this is not set, it uses Jersey's internal JSON provider(s) to deserialize/serialize. I am not sure sure how to configure the default providers, but I think it's safer to just go with Jackson anyway.


Aside, in my comments above I was saying to test if Jackson is being used. One way to easily accomplish this is to just create a ContextResolver and and a s.o.p. inside the getContext method. This method is called when the mapper is needed. So if Jackson is being used, the s.o.p should print

@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;
    }  
}

Note that this is also a way to make any configurations with the Jackson serization/deserialization (just configure the mapper).




回答2:


May be you want to use GenericEntity and return 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();
}


来源:https://stackoverflow.com/questions/32097870/expected-an-array-of-objects-but-got-an-object-in-an-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!