001/*
002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nicolas Chapurlat <nchapurlat@nuxeo.com>
016 */
017
018package org.nuxeo.ecm.core.io.marshallers.json;
019
020import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
021
022import java.io.IOException;
023import java.lang.reflect.Type;
024import java.util.ArrayList;
025import java.util.Iterator;
026import java.util.List;
027
028import org.apache.commons.lang3.reflect.TypeUtils;
029import org.codehaus.jackson.JsonNode;
030import org.nuxeo.ecm.core.io.registry.MarshallerRegistry;
031import org.nuxeo.ecm.core.io.registry.Reader;
032
033/**
034 * Base class to convert json as {@link List}.
035 * <p>
036 * It follow the classic Nuxeo list format :
037 *
038 * <pre>
039 * {
040 *   "entity-type": "GIVEN_ENTITY_TYPE",
041 *   "entries": [
042 *     {...}, <-- A {@link Reader} must be able to manage this format.
043 *     {...},
044 *     ...
045 *     {...}
046 *   ]
047 * }
048 * </pre>
049 *
050 * </p>
051 * <p>
052 * This reader delegates the unmarshalling of entries to the {@link MarshallerRegistry}. A Json {@link Reader}
053 * compatible with the required type and the json format must be registered.
054 * </p>
055 *
056 * @param <EntityType> The type of the element of this list.
057 * @since 7.2
058 */
059public abstract class DefaultListJsonReader<EntityType> extends EntityJsonReader<List<EntityType>> {
060
061    /**
062     * The Java type of the element of this list.
063     */
064    private final Class<EntityType> elClazz;
065
066    /**
067     * The generic type of the element of this list.
068     */
069    private final Type elGenericType;
070
071    /**
072     * Use this constructor if the element of the list are not based on Java generic type.
073     *
074     * @param entityType The list "entity-type".
075     * @param elClazz The class of the element of the list.
076     */
077    public DefaultListJsonReader(String entityType, Class<EntityType> elClazz) {
078        super(entityType);
079        this.elClazz = elClazz;
080        elGenericType = elClazz;
081    }
082
083    /**
084     * Use this constructor if the element of the list are based on Java generic type.
085     *
086     * @param entityType The list "entity-type".
087     * @param elClazz The class of the element of the list.
088     * @param elGenericType The generic type of the list (you can use {@link TypeUtils#parameterize(Class, Type...) to
089     *            generate it}
090     */
091    public DefaultListJsonReader(String entityType, Class<EntityType> elClazz, Type elGenericType) {
092        super(entityType);
093        this.elClazz = elClazz;
094        this.elGenericType = elGenericType;
095    }
096
097    @Override
098    protected List<EntityType> readEntity(JsonNode jn) throws IOException {
099        Reader<EntityType> entryReader = registry.getReader(ctx, elClazz, elGenericType, APPLICATION_JSON_TYPE);
100        List<EntityType> result = new ArrayList<EntityType>();
101        JsonNode entriesNode = jn.get("entries");
102        if (entriesNode != null && !entriesNode.isNull() && entriesNode.isArray()) {
103            JsonNode entryNode = null;
104            Iterator<JsonNode> it = entriesNode.getElements();
105            while (it.hasNext()) {
106                entryNode = it.next();
107                InputStreamWithJsonNode in = new InputStreamWithJsonNode(entryNode);
108                EntityType doc = entryReader.read(elClazz, elClazz, APPLICATION_JSON_TYPE, in);
109                result.add(doc);
110            }
111        }
112        return result;
113    }
114
115}