java 如何使用 Jersey 将嵌套列表编组为 JSON?我得到一个空数组或一个包含数组的单元素字典数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1145476/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 15:21:53  来源:igfitidea点击:

How do I marshal nested lists as JSON using Jersey? I get an array of nulls or an array of one-element dictionaries containing an array

javaarraysjsonjaxbjersey

提问by

I'm working on a project which uses Jersey to convert objects to JSON. I'd like to be able to write out nested lists, like so:

我正在开发一个使用 Jersey 将对象转换为 JSON 的项目。我希望能够写出嵌套列表,如下所示:

{"data":[["one", "two", "three"], ["a", "b", "c"]]}

The object I'd like to convert first represented data as a <LinkedList<LinkedList<String>>>, and I figured Jersey would just do the right thing. The above was output as a list of nulls:

我想转换的对象首先将数据表示为 <LinkedList<LinkedList<String>>,我认为 Jersey 会做正确的事情。以上输出为空值列表:

{"data":[null, null]}

After reading that nested objects need to be wrapped, I tried the following:

在阅读嵌套对象需要包装后,我尝试了以下操作:

@XmlRootElement(name = "foo")
@XmlType(propOrder = {"data"})
public class Foo
{
    private Collection<FooData> data = new LinkedList<FooData>();

    @XmlElement(name = "data")
    public Collection<FooData> getData()
    {
        return data;
    }

    public void addData(Collection data)
    {
        FooData d = new FooData();
        for(Object o: data)
        {
            d.getData().add(o == null ? (String)o : o.toString());
        }
        this.data.add(d);
    }

    @XmlRootElement(name = "FooData")
    public static class FooData
    {
        private Collection<String> data = new LinkedList<String>();

        @XmlElement
        public Collection<String> getData()
        {
            return data;
        }
    }
}

That code outputs what's below, which is closer to what I want:

该代码输出以下内容,更接近我想要的内容:

{"data":[{"data":["one", "two", "three"]},{"data":["a", "b", "c"]}]}

I want the first data to be a list of lists, not a list of one-element dictionaries. How do I achieve this?

我希望第一个数据是列表列表,而不是单元素字典列表。我如何实现这一目标?

Here's my JAXBContentResolver:

这是我的 JAXBContentResolver:

@Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext>
{
    private JAXBContext context;
    private Set<Class<?>> types;

    // Only parent classes are required here. Nested classes are implicit.
    protected Class<?>[] classTypes = new Class[] {Foo.class};

    protected Set<String> jsonArray = new HashSet<String>(1) {
        {
            add("data");
        }
    };

    public JAXBContextResolver() throws Exception
    {        
        Map<String, Object> props = new HashMap<String, Object>();
        props.put(JSONJAXBContext.JSON_NOTATION, JSONJAXBContext.JSONNotation.MAPPED);
        props.put(JSONJAXBContext.JSON_ROOT_UNWRAPPING, Boolean.TRUE);
        props.put(JSONJAXBContext.JSON_ARRAYS, jsonArray);
        this.types = new HashSet<Class<?>>(Arrays.asList(classTypes));
        this.context = new JSONJAXBContext(classTyes, props);
    }

    public JAXBContext getContext(Class<?> objectType)
    {
        return (types.contains(objectType)) ? context : null;
    }
}

回答by Arnaudweb

Have you tried jersey-json ??

你试过 jersey-json 吗??

Add jersey-json to your classpath (or your maven dependencies)

将 jersey-json 添加到您的类路径(或您的 maven 依赖项)

Then use this :

然后使用这个:

@Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext> {

    private final JAXBContext context;

    public JAXBContextResolver() throws Exception {
        this.context = new JSONJAXBContext(JSONConfiguration.natural().build(), "package.of.your.model");
    }

    public JAXBContext getContext(Class<?> objectType) {
        return context;
    }

}

You only need something like this in your ressources (supposing DetailProduit is your object you want to serialize and that DetailProduit.java is jaxb tagged and in package.of.your.model)

你只需要在你的资源中这样的东西(假设 DetailProduit 是你想要序列化的对象,并且 DetailProduit.java 是 jaxb 标记并在 package.of.your.model 中)

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{code}")
public DetailProduit getDetailProduit(@PathParam("code") String code) {
        .... Your Code ........
    }

回答by anon

Check out the "Improving the Application" section of this page:

查看此页面的“改进应用程序”部分:

http://blogs.oracle.com/enterprisetechtips/entry/configuring_json_for_restful_web

http://blogs.oracle.com/enterprisetechtips/entry/configuring_json_for_restful_web

回答by Perty

I know the qustion is rather old but I stumbled on a similar problem but I wanted to render a List of Arrays ie.′List′ due to a result from a db which I got from jpa and a nativ query without using Entities.

我知道这个问题很旧,但我偶然发现了一个类似的问题,但我想渲染一个数组列表 ie.'List' 由于我从 jpa 和一个 nativ 查询中获得的结果而不使用实体。

This is how I solved it:

我是这样解决的:

First Created a ListWrapper.java:

首先创建一个ListWrapper.java:

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class ListWrapper extends ArrayList {

    @SuppressWarnings("unchecked")
    public ListWrapper() {
        super();
    }

    public ListWrapper(List list) {
        super(list);
    }
}

And then I created a class extending AbstractMessageReaderWriterProvider

然后我创建了一个扩展 AbstractMessageReaderWriterProvider 的类

import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;

import com.sun.jersey.core.provider.AbstractMessageReaderWriterProvider;

@Provider
@Produces("*/*")
@Consumes("*/*")
public class ListObjectArrayMessagereaderWriterProvider extends    AbstractMessageReaderWriterProvider<ListWrapper> {

    public boolean supports(Class type) {
        return type == ListWrapper.class;
    }

    @Override
    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return type == ListWrapper.class;
    }

    @Override
    public ListWrapper readFrom(Class<ListWrapper> type, Type genericType, Annotation[] annotations, MediaType mediaType,
        MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
        throw new IllegalArgumentException("Not implemented yet.");
    }

    @Override
    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return type == ListWrapper.class;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void writeTo(ListWrapper t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
        MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {

        final Iterator<Object[]> iterator = t.iterator();

        OutputStreamWriter writer = new OutputStreamWriter(entityStream, getCharset(mediaType));
        final JSONArray jsonArrayOuter = new JSONArray();
        while (iterator.hasNext()) {
            final Object[] objs = iterator.next();
            JSONArray jsonArrayInner = new JSONArray(Arrays.asList(objs));
            jsonArrayOuter.put(jsonArrayInner);
        }
        try {
            jsonArrayOuter.write(writer);
            writer.write("\n");
            writer.flush();
        } catch (JSONException je) {
            throw new WebApplicationException(new Exception(ImplMessages.ERROR_WRITING_JSON_ARRAY(), je), 500);
        }
    }
}

Then I using it in a as this:

然后我在 a 中使用它,如下所示:

    @GET
    @Path("/{id}/search")
    @Produces(JSON)
    public ListWrapper search(@PathParam("id") Integer projectId ) {
        return DatabaseManager.search(projectId);
    }

The search method is returning a Listwrapper with a list of Object[]

搜索方法返回一个包含 Object[] 列表的 Listwrapper

Hope this helps someone :-)

希望这对某人有所帮助:-)