com.msopentech.odatajclient.engine.data.Deserializer.java Source code

Java tutorial

Introduction

Here is the source code for com.msopentech.odatajclient.engine.data.Deserializer.java

Source

/**
 * Copyright  Microsoft Open Technologies, Inc.
 *
 * All Rights Reserved
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
 * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
 * ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A
 * PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT.
 *
 * See the Apache License, Version 2.0 for the specific language
 * governing permissions and limitations under the License.
 */
package com.msopentech.odatajclient.engine.data;

import com.fasterxml.aalto.stax.InputFactoryImpl;
import com.fasterxml.aalto.stax.OutputFactoryImpl;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule;
import com.fasterxml.jackson.dataformat.xml.XmlFactory;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.msopentech.odatajclient.engine.data.atom.AtomDeserializer;
import com.msopentech.odatajclient.engine.data.atom.AtomEntry;
import com.msopentech.odatajclient.engine.data.atom.AtomFeed;
import com.msopentech.odatajclient.engine.data.json.JSONEntry;
import com.msopentech.odatajclient.engine.data.json.JSONFeed;
import com.msopentech.odatajclient.engine.data.json.JSONLinkCollection;
import com.msopentech.odatajclient.engine.data.json.JSONProperty;
import com.msopentech.odatajclient.engine.data.json.JSONServiceDocument;
import com.msopentech.odatajclient.engine.data.json.error.JSONODataError;
import com.msopentech.odatajclient.engine.data.json.error.JSONODataErrorBundle;
import com.msopentech.odatajclient.engine.data.metadata.edm.AbstractAnnotatedEdm;
import com.msopentech.odatajclient.engine.data.metadata.edm.AbstractAnnotatedEdmUtils;
import com.msopentech.odatajclient.engine.data.metadata.edm.Edmx;
import com.msopentech.odatajclient.engine.data.xml.XMLLinkCollection;
import com.msopentech.odatajclient.engine.data.xml.XMLServiceDocument;
import com.msopentech.odatajclient.engine.data.xml.XMLODataError;
import com.msopentech.odatajclient.engine.format.ODataFormat;
import com.msopentech.odatajclient.engine.utils.ODataConstants;
import com.msopentech.odatajclient.engine.utils.XMLUtils;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 * Utility class for serialization.
 */
public final class Deserializer {

    private Deserializer() {
        // Empty private constructor for static utility classes
    }

    public static Edmx toMetadata(final InputStream input) {
        try {
            final XmlMapper xmlMapper = new XmlMapper(
                    new XmlFactory(new InputFactoryImpl(), new OutputFactoryImpl()), new JacksonXmlModule());
            xmlMapper.addHandler(new DeserializationProblemHandler() {

                @Override
                public boolean handleUnknownProperty(final DeserializationContext ctxt, final JsonParser jp,
                        final JsonDeserializer<?> deserializer, final Object beanOrClass, final String propertyName)
                        throws IOException, JsonProcessingException {

                    // 1. special handling of AbstractAnnotatedEdm's fields
                    if (beanOrClass instanceof AbstractAnnotatedEdm
                            && AbstractAnnotatedEdmUtils.isAbstractAnnotatedProperty(propertyName)) {

                        AbstractAnnotatedEdmUtils.parseAnnotatedEdm((AbstractAnnotatedEdm) beanOrClass, jp);
                    } // 2. skip any other unknown property
                    else {
                        ctxt.getParser().skipChildren();
                    }

                    return true;
                }
            });
            return xmlMapper.readValue(input, Edmx.class);
        } catch (Exception e) {
            throw new IllegalArgumentException("Could not parse as Edmx document", e);
        }
    }

    /**
     * Gets a feed object from the given InputStream.
     *
     * @param <T> reference class type
     * @param input stream to be de-serialized.
     * @param reference reference class (AtomFeed.class, JSONFeed.class).
     * @return FeedResource instance.
     */
    @SuppressWarnings("unchecked")
    public static <T extends FeedResource> T toFeed(final InputStream input, final Class<T> reference) {
        T entry;

        if (AtomFeed.class.equals(reference)) {
            entry = (T) toAtomFeed(input);

        } else {
            entry = (T) toJSONFeed(input);
        }

        return entry;
    }

    /**
     * Gets an entry object from the given InputStream.
     *
     * @param <T> reference class type
     * @param input stream to be de-serialized.
     * @param reference reference class (AtomEntry.class, JSONEntry.class).
     * @return EntryResource instance.
     */
    @SuppressWarnings("unchecked")
    public static <T extends EntryResource> T toEntry(final InputStream input, final Class<T> reference) {
        T entry;

        if (AtomEntry.class.equals(reference)) {
            entry = (T) toAtomEntry(input);

        } else {
            entry = (T) toJSONEntry(input);
        }

        return entry;
    }

    /**
     * Gets a DOM representation of the given InputStream.
     *
     * @param input stream to be de-serialized.
     * @param format OData format.
     * @return DOM.
     */
    public static Element toPropertyDOM(final InputStream input, final ODataFormat format) {
        return format == ODataFormat.XML ? toPropertyDOMFromXML(input) : toPropertyDOMFromJSON(input);
    }

    /**
     * Gets the ServiceDocumentResource object represented by the given InputStream.
     *
     * @param input stream to be de-serialized.
     * @param format OData service document format.
     * @return ServiceDocumentResource object.
     */
    public static ServiceDocumentResource toServiceDocument(final InputStream input, final ODataFormat format) {
        return format == ODataFormat.XML ? toServiceDocumentFromXML(input) : toServiceDocumentFromJSON(input);
    }

    /**
     * Gets a list of links from the given InputStream.
     *
     * @param input stream to be de-serialized.
     * @param format OData format.
     * @return de-serialized links.
     */
    public static LinkCollectionResource toLinkCollection(final InputStream input, final ODataFormat format) {
        return format == ODataFormat.XML ? toLinkCollectionFromXML(input) : toLinkCollectionFromJSON(input);
    }

    /**
     * Gets the ODataError object represented by the given InputStream.
     *
     * @param input stream to be parsed and de-serialized.
     * @param isXML 'TRUE' if the error is represented by XML; 'FALSE' otherwise.
     * @return
     */
    public static ODataError toODataError(final InputStream input, final boolean isXML) {
        return isXML ? toODataErrorFromXML(input) : toODataErrorFromJSON(input);
    }

    /**
     * Parses the given input into a DOM tree.
     *
     * @param input stream to be parsed and de-serialized.
     * @return DOM tree
     */
    public static Element toDOM(final InputStream input) {
        return XMLUtils.PARSER.parse(input);
    }

    /*
     * ------------------ Private methods ------------------
     */
    @SuppressWarnings("unchecked")
    private static AtomFeed toAtomFeed(final InputStream input) {
        try {
            return AtomDeserializer.feed(toDOM(input));
        } catch (Exception e) {
            throw new IllegalArgumentException("While deserializing Atom feed", e);
        }
    }

    @SuppressWarnings("unchecked")
    private static AtomEntry toAtomEntry(final InputStream input) {
        try {
            return AtomDeserializer.entry(toDOM(input));
        } catch (Exception e) {
            throw new IllegalArgumentException("While deserializing Atom entry", e);
        }
    }

    private static JSONFeed toJSONFeed(final InputStream input) {
        try {
            final ObjectMapper mapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);

            return mapper.readValue(input, JSONFeed.class);
        } catch (IOException e) {
            throw new IllegalArgumentException("While deserializing JSON feed", e);
        }
    }

    private static JSONEntry toJSONEntry(final InputStream input) {
        try {
            final ObjectMapper mapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);

            return mapper.readValue(input, JSONEntry.class);
        } catch (IOException e) {
            throw new IllegalArgumentException("While deserializing JSON entry", e);
        }
    }

    private static Element toPropertyDOMFromXML(final InputStream input) {
        return toDOM(input);
    }

    private static Element toPropertyDOMFromJSON(final InputStream input) {
        try {
            final ObjectMapper mapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);

            return mapper.readValue(input, JSONProperty.class).getContent();
        } catch (IOException e) {
            throw new IllegalArgumentException("While deserializing JSON property", e);
        }
    }

    private static ServiceDocumentResource toServiceDocumentFromXML(final InputStream input) {
        final Element service = toDOM(input);

        final XMLServiceDocument serviceDoc = new XMLServiceDocument();
        serviceDoc.setBaseURI(URI.create(service.getAttribute(ODataConstants.ATTR_XMLBASE)));

        final NodeList collections = service.getElementsByTagName(ODataConstants.ELEM_COLLECTION);
        for (int i = 0; i < collections.getLength(); i++) {
            final Element collection = (Element) collections.item(i);

            final NodeList title = collection.getElementsByTagName(ODataConstants.ATOM_ATTR_TITLE);
            if (title.getLength() != 1) {
                throw new IllegalArgumentException("Invalid collection element found");
            }

            serviceDoc.addToplevelEntitySet(title.item(0).getTextContent(),
                    collection.getAttribute(ODataConstants.ATTR_HREF));
        }

        return serviceDoc;
    }

    private static ServiceDocumentResource toServiceDocumentFromJSON(final InputStream input) {
        try {
            final ObjectMapper mapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);

            return mapper.readValue(input, JSONServiceDocument.class);
        } catch (IOException e) {
            throw new IllegalArgumentException("While deserializing JSON service document", e);
        }
    }

    private static XMLLinkCollection toLinkCollectionFromXML(final InputStream input) {
        final Element root = toDOM(input);

        final NodeList uris = root.getOwnerDocument().getElementsByTagName(ODataConstants.ELEM_URI);

        final List<URI> links = new ArrayList<URI>();
        for (int i = 0; i < uris.getLength(); i++) {
            links.add(URI.create(uris.item(i).getTextContent()));
        }

        final NodeList next = root.getElementsByTagName(ODataConstants.NEXT_LINK_REL);
        final XMLLinkCollection linkCollection = next.getLength() > 0
                ? new XMLLinkCollection(URI.create(next.item(0).getTextContent()))
                : new XMLLinkCollection();
        linkCollection.setLinks(links);

        return linkCollection;
    }

    private static JSONLinkCollection toLinkCollectionFromJSON(final InputStream input) {
        try {
            final ObjectMapper mapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);

            return mapper.readValue(input, JSONLinkCollection.class);
        } catch (IOException e) {
            throw new IllegalArgumentException("While deserializing JSON $links", e);
        }
    }

    private static XMLODataError toODataErrorFromXML(final InputStream input) {
        try {
            final XmlMapper xmlMapper = new XmlMapper(
                    new XmlFactory(new InputFactoryImpl(), new OutputFactoryImpl()), new JacksonXmlModule());
            return xmlMapper.readValue(input, XMLODataError.class);
        } catch (Exception e) {
            throw new IllegalArgumentException("While deserializing XML error", e);
        }
    }

    private static JSONODataError toODataErrorFromJSON(final InputStream input) {
        try {
            final ObjectMapper mapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);

            return mapper.readValue(input, JSONODataErrorBundle.class).getError();
        } catch (IOException e) {
            throw new IllegalArgumentException("While deserializing JSON error", e);
        }
    }
}