001/*
002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nicolas Chapurlat <nchapurlat@nuxeo.com>
018 */
019
020package org.nuxeo.ecm.core.io.marshallers.json;
021
022import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
023
024import java.io.IOException;
025import java.lang.reflect.Type;
026import java.util.ArrayList;
027import java.util.Iterator;
028import java.util.List;
029
030import org.apache.commons.lang3.reflect.TypeUtils;
031import org.nuxeo.ecm.core.io.registry.MarshallerRegistry;
032import org.nuxeo.ecm.core.io.registry.Reader;
033
034import com.fasterxml.jackson.databind.JsonNode;
035
036/**
037 * Base class to convert json as {@link List}.
038 * <p>
039 * It follow the classic Nuxeo list format :
040 *
041 * <pre>
042 * {
043 *   "entity-type": "GIVEN_ENTITY_TYPE",
044 *   "entries": [
045 *     {...}, <-- A {@link Reader} must be able to manage this format.
046 *     {...},
047 *     ...
048 *     {...}
049 *   ]
050 * }
051 * </pre>
052 *
053 * </p>
054 * <p>
055 * This reader delegates the unmarshalling of entries to the {@link MarshallerRegistry}. A Json {@link Reader}
056 * compatible with the required type and the json format must be registered.
057 * </p>
058 *
059 * @param <EntityType> The type of the element of this list.
060 * @since 7.2
061 */
062public abstract class DefaultListJsonReader<EntityType> extends EntityJsonReader<List<EntityType>> {
063
064    /**
065     * The Java type of the element of this list.
066     */
067    private final Class<EntityType> elClazz;
068
069    /**
070     * The generic type of the element of this list.
071     */
072    private final Type elGenericType;
073
074    /**
075     * Use this constructor if the element of the list are not based on Java generic type.
076     *
077     * @param entityType The list "entity-type".
078     * @param elClazz The class of the element of the list.
079     */
080    public DefaultListJsonReader(String entityType, Class<EntityType> elClazz) {
081        super(entityType);
082        this.elClazz = elClazz;
083        elGenericType = elClazz;
084    }
085
086    /**
087     * Use this constructor if the element of the list are based on Java generic type.
088     *
089     * @param entityType The list "entity-type".
090     * @param elClazz The class of the element of the list.
091     * @param elGenericType The generic type of the list (you can use {@link TypeUtils#parameterize(Class, Type...) to
092     *            generate it}
093     */
094    public DefaultListJsonReader(String entityType, Class<EntityType> elClazz, Type elGenericType) {
095        super(entityType);
096        this.elClazz = elClazz;
097        this.elGenericType = elGenericType;
098    }
099
100    @Override
101    protected List<EntityType> readEntity(JsonNode jn) throws IOException {
102        Reader<EntityType> entryReader = registry.getReader(ctx, elClazz, elGenericType, APPLICATION_JSON_TYPE);
103        List<EntityType> result = new ArrayList<EntityType>();
104        JsonNode entriesNode = jn.get("entries");
105        if (entriesNode != null && !entriesNode.isNull() && entriesNode.isArray()) {
106            JsonNode entryNode = null;
107            Iterator<JsonNode> it = entriesNode.elements();
108            while (it.hasNext()) {
109                entryNode = it.next();
110                InputStreamWithJsonNode in = new InputStreamWithJsonNode(entryNode);
111                EntityType doc = entryReader.read(elClazz, elClazz, APPLICATION_JSON_TYPE, in);
112                result.add(doc);
113            }
114        }
115        return result;
116    }
117
118}