com.karlstein.tools.serializer.JsonSerializer.java Source code

Java tutorial

Introduction

Here is the source code for com.karlstein.tools.serializer.JsonSerializer.java

Source

/*
 * Copyright 2014 Karl STEIN
 *
 * 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
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.karlstein.tools.serializer;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * This class is used to read/write JSON data
 *
 * @author Karl STEIN
 */
public class JsonSerializer extends KSerializer {

    /**
     * Creates a JSON converter
     */
    public JsonSerializer() {
        // Use four spaces for indentation
        setIndentationCharacter("    ");
    }

    @Override
    protected boolean checkField(final Field field) {
        final Class<?> cls = field.getType();

        // Convert these field types only
        return super.checkField(field) && (cls.isPrimitive() || cls.isEnum() || cls.equals(String.class)
                || cls.equals(Character.class) || cls.equals(Boolean.class) || Number.class.isAssignableFrom(cls)
                || Date.class.isAssignableFrom(cls) || Object.class.isAssignableFrom(cls));
    }

    /**
     * Escapes all quotes in the value
     *
     * @param value the value to escape
     * @return CharSequence
     */
    protected CharSequence escapeValue(String value) {
        if (value != null && value.indexOf('"') > 0) {
            value = value.replace("\"", "\\\"");
            value = value.replace("\r", "\\r");
            value = value.replace("\n", "\\n");
        }
        return value;
    }

    @Override
    public <T> T read(Class<T> cls, Reader reader) {
        Gson gson = new Gson();
        GsonBuilder builder = new GsonBuilder();
        builder.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
        return builder.create().fromJson(reader, cls);
    }

    /**
     * Writes a collection
     *
     * @param collection the collection to write
     * @param writer     the writer
     * @return Writer
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     * @throws IOException
     */
    public Writer write(final Collection<?> collection, final Writer writer)
            throws IllegalArgumentException, IllegalAccessException, IOException {
        // Open the collection
        writer.append('[');
        writeLineFeed(writer);
        increaseIndentation();

        final Iterator<?> iterator = collection.iterator();

        while (iterator.hasNext()) {
            final Object element = iterator.next();

            // Check if the element should be ignored
            if (element != null && ignoredObjects.contains(element)) {
                continue;
            }

            // Add the element
            writeIndentation(writer);
            write(element, writer);

            if (iterator.hasNext()) {
                writer.append(",");
            }
            writeLineFeed(writer);
        }

        // Close the collection
        decreaseIndentation();
        writeIndentation(writer);
        writer.append(']');

        return writer;
    }

    /**
     * Writes a map
     *
     * @param map    the map to write
     * @param writer the writer
     * @return Writer
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     * @throws IOException
     */
    public Writer write(final Map<?, ?> map, final Writer writer)
            throws IllegalArgumentException, IllegalAccessException, IOException {
        // Open the object
        writer.append('{');
        writeLineFeed(writer);
        increaseIndentation();

        final Iterator<?> iterator = map.keySet().iterator();

        while (iterator.hasNext()) {
            final Object key = iterator.next();
            final Object value = map.get(key);

            // Check if the value should be ignored
            if (value != null && ignoredObjects.contains(value)) {
                continue;
            }

            // Add the field name
            writeIndentation(writer);
            writer.write("\"" + key + "\"");
            writeSpace(writer);
            writer.write(':');
            writeSpace(writer);

            // Add the field value
            write(value, writer);

            if (iterator.hasNext()) {
                writer.append(',');
            }
            writeLineFeed(writer);
        }

        // Close the object
        decreaseIndentation();
        writeIndentation(writer);
        writer.append('}');

        return writer;
    }

    @Override
    protected Writer writeLineFeed(Writer writer) throws IOException {
        return compressOutput ? writer : super.writeLineFeed(writer);
    }

    @Override
    public Writer write(final Object object, final Writer writer)
            throws IOException, IllegalArgumentException, IllegalAccessException {
        if (object == null) {
            writer.append("null");

        } else {
            final Class<?> cls = object.getClass();

            if (Date.class.isAssignableFrom(cls)) {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
                writer.append('"');
                writer.append(escapeValue(df.format(object)));
                writer.append('"');

            } else if (cls.equals(String.class) || cls.isEnum() || cls.equals(Character.class)
                    || cls.equals(Character.TYPE)) {
                // Escape quotes when the object is a string
                writer.write("\"" + escapeValue(String.valueOf(object)) + "\"");

            } else if (cls.isPrimitive() || cls.equals(Boolean.class) || Number.class.isInstance(object)) {
                writer.append(String.valueOf(object));

            } else if (List.class.isInstance(object) || Set.class.isInstance(object)) {
                write((Collection<?>) object, writer);

            } else if (Map.class.isInstance(object)) {
                write((Map<?, ?>) object, writer);

            } else if (cls.isArray()) {
                write(getCollectionFromObject(object), writer);

            } else {
                // Ignore this class next time
                ignoredObjects.add(object);

                // Open the object
                writer.append('{');
                writeLineFeed(writer);
                increaseIndentation();

                // Get the object fields
                final Set<Field> fields = getFields(object.getClass());
                final Iterator<Field> iterator = fields.iterator();

                while (iterator.hasNext()) {
                    final Field field = iterator.next();
                    final Object value = field.get(object);

                    // Check if the value should be ignored
                    if (value != null && ignoredObjects.contains(value)) {
                        continue;
                    }

                    // Add the field name
                    writeIndentation(writer);
                    writer.write("\"" + field.getName() + "\"");
                    writeSpace(writer);
                    writer.write(':');
                    writeSpace(writer);

                    // Add the field value
                    write(value, writer);

                    if (iterator.hasNext()) {
                        writer.append(',');
                    }
                    writeLineFeed(writer);
                }
                ignoredObjects.remove(object);

                // Close the object
                decreaseIndentation();
                writeIndentation(writer);
                writer.append('}');
            }
        }
        return writer;
    }

    @Override
    protected Writer writeSpace(Writer writer) throws IOException {
        return compressOutput ? writer : super.writeSpace(writer);
    }
}