Jersey: Json array with 1 element is serialized as

2020-03-01 04:15发布

I'm creating a REST server with Jersey/Java and I found a strange behavior.

I have a method on the server that returns an array of objects as Json

@GET
@Path("/files")
@Produces(MediaType.APPLICATION_JSON)
public Object getFiles() throws Exception{
    DatabaseManager db = new DatabaseManager();
    FileInfo[] result = db.getFiles();
    return result;
}

The code is executed correctly and data is returned to the client (a jQuery ajax call). The problem is that the format of the returned data changes if the "result" array has one element or more than one.

Response with one element:

{"fileInfo":{"fileName":"weather.arff","id":"10"}}

Response with two elements:

{"fileInfo":[{"fileName":"weather.arff","id":"10"},{"fileName":"supermarket.arff","id":"11"}]}

As you can see, in the first scenario the value of the "fileInfo" property of the returned object is an object, and in the second case the value is an array. What am I doing wrong? Shouldn't the first case return something like this:

{"fileInfo":[{"fileName":"weather.arff","id":"10"}]}

i.e. an array with a single object inside?

I know that I can detect this on the client side, but it seems like a very ugly hack.

Thanks for your time.

8条回答
我欲成王,谁敢阻挡
2楼-- · 2020-03-01 05:07

Converting the Array into ArrayList would suffice the requirement here. Similar kind of contradictory issue I have faced, where I had to return the Json Array Object instead of list in case of single element.

There i took the help of below annotation to get my job done-

@JsonFormat(with = JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED). Below is the example of a JSON Pojo class:

import java.util.List;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonIgnoreProperties(ignoreUnknown = true)
public class TAResponseMapper {

    @JsonProperty("Response")
    @JsonFormat(with = JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED) 
    private List<TAResponse> responses;

    public List<TAResponse> getResponses() {
        return responses;
    }

    public void setResponses(List<TAResponse> responses) {
        this.responses = responses;
    }

}
查看更多
劫难
3楼-- · 2020-03-01 05:08

If you were using JAXB to build JSON result, you can configure Jersey JSON procesor to get more important JSON format.

jersey official document has detailed config:

To achieve more important JSON format changes, you will need to configure Jersey JSON procesor itself. Various configuration options could be set on an JSONConfiguration instance. The instance could be then further used to create a JSONConfigurated JSONJAXBContext, which serves as a main configuration point in this area. To pass your specialized JSONJAXBContext to Jersey, you will finally need to implement a JAXBContext ContextResolver:

    @Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext> {
    private final JAXBContext context;
    private final Set<Class> types;
    private Class[] ctypes = { FileInfo.class}; //your pojo class
    public JAXBContextResolver() throws Exception {
        this.types = new HashSet(Arrays.asList(ctypes));
        this.context = new JSONJAXBContext(JSONConfiguration.natural().build(),
                ctypes); //json configuration
    }

    @Override
    public JAXBContext getContext(Class<?> objectType) {
        return (types.contains(objectType)) ? context : null;
    }
}
查看更多
登录 后发表回答