org.emfjson.jackson.streaming.StreamWriter.java Source code

Java tutorial

Introduction

Here is the source code for org.emfjson.jackson.streaming.StreamWriter.java

Source

/*
 * Copyright (c) 2011-2014 Guillaume Hillairet.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Guillaume Hillairet - initial API and implementation
 */
package org.emfjson.jackson.streaming;

import static org.emfjson.common.Constants.EJS_TYPE_KEYWORD;
import static org.emfjson.common.Constants.EJS_UUID_ANNOTATION;
import static org.emfjson.common.EObjects.featureMaps;
import static org.emfjson.common.EObjects.isCandidate;
import static org.emfjson.common.EObjects.isContainmentProxy;
import static org.emfjson.common.EObjects.isFeatureMap;
import static org.emfjson.common.EObjects.isMapEntry;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.emfjson.common.Cache;
import org.emfjson.common.Options;
import org.emfjson.common.resource.UuidResource;
import org.emfjson.converters.DataTypeConverter;
import org.emfjson.jackson.converters.DefaultDateConverter;
import org.emfjson.jackson.streaming.References.RefAsObjectWriter;
import org.emfjson.jackson.streaming.References.RefWriter;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;

public class StreamWriter {

    private final Options options;
    private final Cache cache = new Cache();

    private References referenceWriter;
    private Values values;

    private Map<EDataType, DataTypeConverter<?, ?>> converters = new HashMap<>();

    private boolean isPrepared = false;
    private RefWriter refWriter;

    public StreamWriter(Options options) {
        this.options = options;
    }

    public void setRefWriter(RefWriter refWriter) {
        this.refWriter = refWriter;
    }

    public void register(DataTypeConverter<?, ?> converter) {
        if (converter != null && converter.getDataType() != null) {
            this.converters.put(converter.getDataType(), converter);
        }
    }

    private void prepare(JsonGenerator generator, Resource resource) {
        if (isPrepared)
            return;

        if (options.indentOutput) {
            DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
            generator.setPrettyPrinter(printer);
        }

        if (refWriter == null) {
            refWriter = new RefAsObjectWriter();
        }

        if (!converters.containsKey(EcorePackage.Literals.EDATE)) {
            converters.put(EcorePackage.Literals.EDATE, new DefaultDateConverter());
        }

        referenceWriter = new References(cache, resource, refWriter, options);
        values = new Values(converters);

        isPrepared = true;
    }

    public void generate(final JsonGenerator generator, Resource resource) {
        prepare(generator, resource);

        final EList<EObject> contents = resource.getContents();

        if (contents.size() == 1) {
            try {
                generate(generator, contents.get(0));
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            try {
                generator.writeStartArray();
                for (final EObject current : contents) {
                    generate(generator, current);
                }
                generator.writeEndArray();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void generate(final JsonGenerator generator, final EObject object) throws IOException {
        prepare(generator, object.eResource());

        final EClass eClass = object.eClass();
        final List<EAttribute> attributes = cache.getAttributes(eClass);
        final List<EReference> references = cache.getReferences(eClass);

        generator.writeStartObject();

        if (options.serializeTypes) {
            generator.writeStringField(EJS_TYPE_KEYWORD, cache.getHref(null, eClass));
        }

        if (object.eResource() instanceof UuidResource) {
            String id = ((UuidResource) object.eResource()).getID(object);
            if (id != null) {
                generator.writeStringField(EJS_UUID_ANNOTATION, id);
            }
        } else {
            if (options.useId) {
                String id = object.eResource().getURIFragment(object);
                if (id != null) {
                    generator.writeStringField(EJS_UUID_ANNOTATION, id);
                }
            }
        }

        for (final EAttribute attribute : attributes) {
            if (isCandidate(object, attribute)) {
                final String key = cache.getKey(attribute);
                final Object value = object.eGet(attribute);

                if (isFeatureMap(attribute)) {
                    serializeFeatureMap(generator, attribute, object);
                } else {
                    values.serialize(generator, key, attribute, value);
                }
            }
        }

        for (final EReference reference : references) {
            if (isCandidate(object, reference)) {
                final Object value = object.eGet(reference);
                final String key = cache.getKey(reference);

                if (isMapEntry(reference.getEReferenceType())) {
                    serializeMapEntry(generator, key, reference, value);
                } else if (!reference.isContainment()) {
                    referenceWriter.serialize(generator, key, reference, value);
                } else {
                    serializeContainment(generator, key, reference, object, value);
                }
            }
        }

        generator.writeEndObject();
    }

    private void serializeMapEntry(JsonGenerator generator, String key, EReference reference, Object value)
            throws IOException {

        generator.writeFieldName(key);
        generator.writeStartObject();

        if (reference.isMany()) {
            @SuppressWarnings("unchecked")
            Collection<Map.Entry<String, String>> entries = (Collection<Entry<String, String>>) value;

            for (Map.Entry<String, String> entry : entries) {
                generator.writeStringField(entry.getKey(), entry.getValue());
            }
        } else {
            @SuppressWarnings("unchecked")
            Map.Entry<String, String> entry = (Entry<String, String>) value;
            generator.writeStringField(entry.getKey(), entry.getValue());
        }
        generator.writeEndObject();
    }

    private void serializeFeatureMap(JsonGenerator generator, EAttribute attribute, EObject owner)
            throws IOException {

        final Set<EStructuralFeature> features = featureMaps(owner, attribute);

        for (EStructuralFeature feature : features) {
            final Object value = owner.eGet(feature);
            final String key = cache.getKey(feature);

            if (feature instanceof EAttribute) {
                values.serialize(generator, key, (EAttribute) feature, value);
            } else {
                final EReference reference = (EReference) feature;
                if (reference.isContainment()) {
                    serializeContainment(generator, key, reference, owner, value);
                } else {
                    referenceWriter.serialize(generator, key, reference, value);
                }
            }
        }
    }

    private void serializeContainment(JsonGenerator generator, String key, EReference containment, EObject owner,
            Object value) throws IOException {

        if (containment.isMany()) {
            final Collection<?> values = (Collection<?>) value;

            generator.writeFieldName(key);
            generator.writeStartArray();
            for (Object current : values) {
                EObject target = (EObject) current;

                if (isContainmentProxy(owner, target)) {
                    referenceWriter.writeRef(generator, target);
                } else {
                    generate(generator, target);
                }

            }
            generator.writeEndArray();

        } else {

            generator.writeFieldName(key);
            if (isContainmentProxy(owner, (EObject) value)) {
                referenceWriter.writeRef(generator, (EObject) value);
            } else {
                generate(generator, (EObject) value);
            }

        }
    }

}