org.gwt.json.serialization.SerializerGenerator.java Source code

Java tutorial

Introduction

Here is the source code for org.gwt.json.serialization.SerializerGenerator.java

Source

/*
 * 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 org.gwt.json.serialization;

import java.io.PrintWriter;
import java.util.*;

import com.google.gwt.core.ext.*;
import com.google.gwt.core.ext.typeinfo.*;
import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JConstructor;
import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.javac.typemodel.*;
import com.google.gwt.dev.javac.typemodel.JRealClassType;
import com.google.gwt.json.client.JSONArray;
import org.apache.commons.lang3.StringUtils;
import org.gwt.json.serialization.client.*;

import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import org.gwt.json.serialization.client.collections.*;
import org.gwt.json.serialization.client.common.JsonDateSerializer;
import org.gwt.json.serialization.client.common.JsonStringSerializer;
import org.gwt.json.serialization.client.primitives.*;
import org.gwt.json.serialization.client.utils.JsonHashMapSerializer;
import org.gwt.json.serialization.client.utils.JsonMapSerializer;
import org.gwt.json.serialization.client.utils.JsonTreeMapSerializer;

/**
 * @author andrii borovyk 06.07.2015
 */
public class SerializerGenerator extends Generator {

    public static final String DATE_FORMAT_PROPERTY = "default.date.format";

    //TODO should be configurable
    private String dateFormat = "yyyy-MM-dd";

    private Set<JArrayType> jArrayTypes;

    private Set<JArrayType> generatedTypes;

    @Override
    public String generate(TreeLogger logger, GeneratorContext context, String typeName)
            throws UnableToCompleteException {

        Map<String, String> serializers = new HashMap<String, String>();
        List<JClassType> genericSerializableTypes = new LinkedList<JClassType>();
        TypeOracle typeOracle = context.getTypeOracle();

        JClassType[] allTypes = typeOracle.getTypes();
        for (JClassType jClassType : allTypes) {

            Serializable annotation = jClassType.getAnnotation(Serializable.class);
            if (annotation != null && !jClassType.isAbstract()) {
                //Ok, this one is a candidate for serializer generation
                if (annotation.customSerializer().length() > 0) {
                    JClassType customSerializer = typeOracle.findType(annotation.customSerializer());
                    if (customSerializer != null) { //generated serializer not required, use specified custom instead
                        serializers.put(jClassType.getQualifiedSourceName(),
                                customSerializer.getQualifiedSourceName());
                    } else {
                        genericSerializableTypes.add(jClassType);
                    }
                } else {
                    genericSerializableTypes.add(jClassType);
                }
            }
        }

        //add default built-in serializers (Collections & primitives)
        //Collection.class.getName()
        //List.class.getName()
        //ArrayList.class.getName()
        //HashSet.class.getName()
        //Date.class.getName()
        //HashMap.class.getName()
        //Map.class.getName()
        //String, Boolean, Integer, Long, Float, Double, Character

        //context.getPropertyOracle().getConfigurationProperty()
        try {
            //primitives
            serializers.put(Float.class.getName(), JsonFloatSerializer.class.getName());
            serializers.put(Double.class.getName(), JsonDoubleSerializer.class.getName());
            serializers.put(Integer.class.getName(), JsonIntegerSerializer.class.getName());
            serializers.put(Long.class.getName(), JsonLongSerializer.class.getName());
            serializers.put(Character.class.getName(), JsonCharacterSerializer.class.getName());
            serializers.put(Boolean.class.getName(), JsonBooleanSerializer.class.getName());
            //common objects
            serializers.put(String.class.getName(), JsonStringSerializer.class.getName());
            serializers.put(Date.class.getName(), JsonDateSerializer.class.getName());

            //collections
            //Collection, List (Linked-, Array-), Set (Hash-, Tree-, LinkedHash-) --> JSONArray
            //Collection, List --> ArrayList, Set -> HashSet
            serializers.put(Collection.class.getName(), JsonCollectionSerializer.class.getName());

            serializers.put(List.class.getName(), JsonListSerializer.class.getName());
            serializers.put(ArrayList.class.getName(), JsonArrayListSerializer.class.getName());
            serializers.put(LinkedList.class.getName(), JsonLinkedListSerializer.class.getName());

            serializers.put(Set.class.getName(), JsonSetSerializer.class.getName());
            serializers.put(HashSet.class.getName(), JsonHashSetSerializer.class.getName());
            serializers.put(TreeSet.class.getName(), JsonTreeSetSerializer.class.getName());
            serializers.put(LinkedHashSet.class.getName(), JsonLinkedHashSetSerializer.class.getName());

            serializers.put(Map.class.getName(), JsonMapSerializer.class.getName());
            serializers.put(HashMap.class.getName(), JsonHashMapSerializer.class.getName());
            serializers.put(TreeMap.class.getName(), JsonTreeMapSerializer.class.getName());

            JClassType classType = context.getTypeOracle().getType(typeName);
            String simpleName = classType.getSimpleSourceName() + "_Generated";

            SourceWriter sourceWriter = getSourceWriter(classType, simpleName, context, logger);
            jArrayTypes = new HashSet<>();
            generatedTypes = new HashSet<>();
            for (JClassType genericClassType : genericSerializableTypes) {
                serializers.put(genericClassType.getQualifiedSourceName(),
                        new InternalSerializerGenerator(genericClassType, jArrayTypes)
                                .generateSerializers(sourceWriter));
            }
            while (!generatedTypes.containsAll(jArrayTypes)) {
                Set<JArrayType> copyOfTypes = new HashSet<>(jArrayTypes);
                for (JArrayType arrayType : copyOfTypes) {
                    if (!generatedTypes.contains(arrayType)) {
                        serializers.put(arrayType.getQualifiedSourceName(),
                                new InternalArraySerializerGenerator(arrayType, jArrayTypes)
                                        .generateSerializers(sourceWriter));
                        generatedTypes.add(arrayType);
                    }
                }
            }
            generateRegisterConstructor(serializers, simpleName, sourceWriter, typeOracle);
            sourceWriter.commit(logger);
            String packageName = classType.getPackage().getName();
            return packageName + "." + simpleName;
        } catch (NotFoundException e) {
            logger.log(TreeLogger.Type.ERROR, e.toString());
            e.printStackTrace();
            throw new UnableToCompleteException();
        }
    }

    protected void generateRegisterConstructor(Map<String, String> serializers, String simpleName,
            SourceWriter writer, TypeOracle typeOracle) {
        writer.println("public " + simpleName + "() {");
        writer.indent();
        for (Map.Entry<String, String> entry : serializers.entrySet()) {
            writer.println("registerSerializer(\"" + entry.getKey() + "\", new " + entry.getValue() + "("
                    + constructorArgsForType(entry.getValue(), typeOracle) + "));");
        }
        writer.outdent();
        writer.println("}");
    }

    protected String constructorArgsForType(String className, TypeOracle typeOracle) {
        if (JsonDateSerializer.class.getName().equals(className)) {
            return "\"" + dateFormat + "\"";
        } else {
            JClassType classType = typeOracle.findType(className);
            if (classType != null) {
                for (JConstructor constructor : classType.getConstructors()) {
                    JType[] types = constructor.getParameterTypes();
                    if (types != null && types.length == 1
                            && Serializer.class.getName().equals(types[0].getQualifiedSourceName())) {
                        return "this";
                    }
                }
            }
        }
        return "";
    }

    protected SourceWriter getSourceWriter(JClassType classType, String simpleName, GeneratorContext context,
            TreeLogger logger) {
        String packageName = classType.getPackage().getName();
        ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(packageName, simpleName);
        composer.setSuperclass(classType.getName());

        composer.addImport(com.google.gwt.core.client.GWT.class.getName());
        composer.addImport(com.google.gwt.json.client.JSONNull.class.getName());
        composer.addImport(com.google.gwt.json.client.JSONNumber.class.getName());
        composer.addImport(com.google.gwt.json.client.JSONString.class.getName());
        composer.addImport(com.google.gwt.json.client.JSONValue.class.getName());
        composer.addImport(com.google.gwt.json.client.JSONObject.class.getName());
        composer.addImport(com.google.gwt.json.client.JSONArray.class.getName());
        composer.addImport(com.google.gwt.json.client.JSONBoolean.class.getName());
        composer.addImport(com.google.gwt.json.client.JSONParser.class.getName());
        composer.addImport(com.google.gwt.json.client.JSONException.class.getName());
        composer.addImport(JsonSimpleTypeSerializer.class.getName());
        composer.addImport(GenericType.class.getName());

        //PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(System.out));
        PrintWriter printWriter = context.tryCreate(logger, packageName, simpleName);
        return (printWriter == null) ? null : composer.createSourceWriter(context, printWriter);
    }
}