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.codehaus.jackson.JsonNode;
032import org.nuxeo.ecm.core.io.registry.MarshallerRegistry;
033import org.nuxeo.ecm.core.io.registry.Reader;
034
035/**
036 * Base class to convert json as {@link List}.
037 * <p>
038 * It follow the classic Nuxeo list format :
039 *
040 * <pre>
041 * {
042 *   "entity-type": "GIVEN_ENTITY_TYPE",
043 *   "entries": [
044 *     {...}, <-- A {@link Reader} must be able to manage this format.
045 *     {...},
046 *     ...
047 *     {...}
048 *   ]
049 * }
050 * </pre>
051 *
052 * </p>
053 * <p>
054 * This reader delegates the unmarshalling of entries to the {@link MarshallerRegistry}. A Json {@link Reader}
055 * compatible with the required type and the json format must be registered.
056 * </p>
057 *
058 * @param <EntityType> The type of the element of this list.
059 * @since 7.2
060 */
061public abstract class DefaultListJsonReader<EntityType> extends EntityJsonReader<List<EntityType>> {
062
063    /**
064     * The Java type of the element of this list.
065     */
066    private final Class<EntityType> elClazz;
067
068    /**
069     * The generic type of the element of this list.
070     */
071    private final Type elGenericType;
072
073    /**
074     * Use this constructor if the element of the list are not based on Java generic type.
075     *
076     * @param entityType The list "entity-type".
077     * @param elClazz The class of the element of the list.
078     */
079    public DefaultListJsonReader(String entityType, Class<EntityType> elClazz) {
080        super(entityType);
081        this.elClazz = elClazz;
082        elGenericType = elClazz;
083    }
084
085    /**
086     * Use this constructor if the element of the list are based on Java generic type.
087     *
088     * @param entityType The list "entity-type".
089     * @param elClazz The class of the element of the list.
090     * @param elGenericType The generic type of the list (you can use {@link TypeUtils#parameterize(Class, Type...) to
091     *            generate it}
092     */
093    public DefaultListJsonReader(String entityType, Class<EntityType> elClazz, Type elGenericType) {
094        super(entityType);
095        this.elClazz = elClazz;
096        this.elGenericType = elGenericType;
097    }
098
099    @Override
100    protected List<EntityType> readEntity(JsonNode jn) throws IOException {
101        Reader<EntityType> entryReader = registry.getReader(ctx, elClazz, elGenericType, APPLICATION_JSON_TYPE);
102        List<EntityType> result = new ArrayList<EntityType>();
103        JsonNode entriesNode = jn.get("entries");
104        if (entriesNode != null && !entriesNode.isNull() && entriesNode.isArray()) {
105            JsonNode entryNode = null;
106            Iterator<JsonNode> it = entriesNode.getElements();
107            while (it.hasNext()) {
108                entryNode = it.next();
109                InputStreamWithJsonNode in = new InputStreamWithJsonNode(entryNode);
110                EntityType doc = entryReader.read(elClazz, elClazz, APPLICATION_JSON_TYPE, in);
111                result.add(doc);
112            }
113        }
114        return result;
115    }
116
117}