Java tutorial
/* * 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); } }