Как маршалировать вложенные списки как JSON, используя Джерси? Я получаю массив нулей или массив одноэлементных словарей, содержащих массив - PullRequest
8 голосов
/ 18 июля 2009

Я работаю над проектом, который использует Джерси для преобразования объектов в JSON. Я хотел бы иметь возможность записывать вложенные списки, например, так:

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

Объект, который я хотел бы преобразовать первыми представленными данными как >>, и я подумал, что Джерси будет делать правильные вещи. Выше было выведено в виде списка нулей:

{"data":[null, null]}

Почитав, что вложенные объекты нужно обернуть, я попытался сделать следующее:

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

Этот код выводит то, что ниже, что ближе к тому, что я хочу:

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

Я хочу, чтобы первыми данными был список списков, а не список одноэлементных словарей. Как мне этого добиться?

Вот мой 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;
    }
}

Ответы [ 3 ]

5 голосов
/ 08 октября 2009

Вы пробовали Джерси-Джсон ??

Добавить jersey-json к вашему classpath (или вашим зависимостям maven)

Тогда используйте это:

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

}

Вам нужно только что-то подобное в ваших ресурсах (предположим, что DetailProduit - это ваш объект, который вы хотите сериализовать, а файл DetailProduit.java помечен jaxb и в package.of.your.model)

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{code}")
public DetailProduit getDetailProduit(@PathParam("code") String code) {
        .... Your Code ........
    }
1 голос
/ 01 сентября 2010

Ознакомьтесь с разделом «Улучшение приложения» на этой странице:

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

0 голосов
/ 03 января 2012

Я знаю, что qasting довольно старый, но я наткнулся на похожую проблему, но я хотел отобразить список массивов, т. Е. «Список» из-за результата из базы данных, полученной из jpa, и нативного запроса без использования сущностей ,

Вот как я это решил:

Сначала создал 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);
    }
}

А потом я создал класс, расширяющий 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);
        }
    }
}

Тогда я использовал его как a:

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

Метод поиска возвращает Listwrapper со списком Object []

Надеюсь, это кому-нибудь поможет: -)

...