问题
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