All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.gsonfire.GsonFireBuilder Maven / Gradle / Ivy

package io.gsonfire;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import io.gsonfire.gson.*;
import io.gsonfire.postprocessors.MergeMapPostProcessor;
import io.gsonfire.postprocessors.methodinvoker.MethodInvokerPostProcessor;
import io.gsonfire.util.Mapper;
import io.gsonfire.util.reflection.CachedReflectionFactory;
import io.gsonfire.util.reflection.Factory;
import io.gsonfire.util.reflection.FieldInspector;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @autor: julio
 */
public final class GsonFireBuilder {

    private final Map classConfigMap = new HashMap();
    private final Map wrappedClasses = new HashMap();
    private final List orderedClasses = new ArrayList();
    private final List serializationExclusions = new ArrayList();
    private final FieldInspector fieldInspector = new FieldInspector();
    private final Factory factory = new CachedReflectionFactory();
    private final Map enumDefaultValues = new HashMap();

    private DateSerializationPolicy dateSerializationPolicy;
    private boolean dateDeserializationStrict = true;
    private TimeZone serializeTimeZone = TimeZone.getDefault();
    private boolean enableExposeMethodResults = false;
    private boolean enableExclusionByValueStrategies = false;

    private ClassConfig getClassConfig(Class clazz){
        ClassConfig result = classConfigMap.get(clazz);
        if(result == null){
            result = new ClassConfig(clazz);
            classConfigMap.put(clazz, result);
            insertOrdered(orderedClasses, clazz);
        }
        return result;
    }

    private static void insertOrdered(List classes, Class clazz) {
        for(int i = classes.size() - 1; i >= 0; i--) {
            Class current = classes.get(i);
            if(current.isAssignableFrom(clazz)) {
                classes.add(i + 1, clazz);
                return;
            }
        }
        classes.add(0, clazz);
    }

    /**
     * Registers a Type selector for the Class specified. 
* A type selector is in charge of deciding which sub class to use when converting a json * into an object.
* See docs and example * @param clazz * @param factory * @param * @return */ public GsonFireBuilder registerTypeSelector(Class clazz, TypeSelector factory){ ClassConfig config = getClassConfig(clazz); config.setTypeSelector(factory); return this; } /** * Registers a Post processor for the Class specified.
* A post processor is a class that will add new fields to a generated json just after generation, or that * will prepare a class just created from a json.
* See docs and example * * @param clazz * @param postProcessor * @param * @return */ public GsonFireBuilder registerPostProcessor(Class clazz, PostProcessor postProcessor){ ClassConfig config = getClassConfig(clazz); config.getPostProcessors().add(postProcessor); return this; } /** * Registers a pre processor for the Class specified.
* A pre processor is a class that will be given the gson to be deserialized in case it wants to change it before * it actually gets deserialized into a class * See docs and example * * @param clazz * @param preProcessor * @param * @return */ public GsonFireBuilder registerPreProcessor(Class clazz, PreProcessor preProcessor){ ClassConfig config = getClassConfig(clazz); config.getPreProcessors().add(preProcessor); return this; } /** * Configures the resulting Gson to serialize/unserialize Date instances with a policy * @param policy * @return */ public GsonFireBuilder dateSerializationPolicy(DateSerializationPolicy policy){ dateSerializationPolicy = policy; return this; } /** * A given class will be wrapped/unwrapped with a given string * during serialization/deserialization. * * @param clazz * @param * @return */ public GsonFireBuilder wrap(final Class clazz, final String name) { wrap(clazz, new Mapper() { @Override public String map(Object from) { return name; } }); return this; } /** * A given class will be wrapped/unwrapped with a string generated by a mapper * during serialization/deserialization. * * @param clazz * @param mapper * @param * @return */ public GsonFireBuilder wrap(Class clazz, Mapper mapper) { wrappedClasses.put(clazz, mapper); return this; } /** * By enabling this, all methods with the annotation {@link io.gsonfire.annotations.ExposeMethodResult} will * be evaluated and it result will be added to the resulting json * @return */ public GsonFireBuilder enableExposeMethodResult(){ this.enableExposeMethodResults = true; return this; } /** * By enabling this, all exclusion by value strategies specified with the annotation * {@link io.gsonfire.annotations.ExcludeByValue} will be run to remove specific fields from the resulting json * @return */ public GsonFireBuilder enableExclusionByValue(){ this.enableExclusionByValueStrategies = true; return this; } /** * By enabling this, all methods with the annotation {@link io.gsonfire.annotations.ExposeMethodResult} will * be evaluated and it result will be added to the resulting json * @return */ public GsonFireBuilder enableHooks(Class clazz){ ClassConfig config = getClassConfig(clazz); config.setHooksEnabled(true); return this; } /** * By enabling this, when a class is being converted to Json and it contains a {@link java.util.Map} class * annotated with {@link io.gsonfire.annotations.MergeMap}, the map will be walked and merged * with the resulting json object. * * This method has been deprecated and a {@link io.gsonfire.PostProcessor} should be used instead * @return */ @Deprecated public GsonFireBuilder enableMergeMaps(Class clazz){ registerPostProcessor(clazz, new MergeMapPostProcessor(fieldInspector)); return this; } /** * Sets the serialization TimeZone. This will affect only values that depend on the TimeZone, for example rfc3339 * dates. * @param timeZone * @return */ public GsonFireBuilder serializeTimeZone(TimeZone timeZone) { this.serializeTimeZone = timeZone; return this; } /** * Defines a default value for an enum when its String representation does not match any of the enum values. * The defaultValue can be null. * @param enumClass * @param defaultValue * @param * @return */ public GsonFireBuilder enumDefaultValue(Class enumClass, T defaultValue) { this.enumDefaultValues.put(enumClass, defaultValue); return this; } public GsonFireBuilder addSerializationExclusionStrategy(FireExclusionStrategy exclusionStrategy) { this.serializationExclusions.add(exclusionStrategy); return this; } /** * Returns a new instance of the good old {@link GsonBuilder} * @return */ public GsonBuilder createGsonBuilder(){ Set alreadyResolvedTypeTokensRegistry = Collections.newSetFromMap(new ConcurrentHashMap()); GsonBuilder builder = new GsonBuilder(); if(enableExposeMethodResults) { FireExclusionStrategy compositeExclusionStrategy = new FireExclusionStrategyComposite(serializationExclusions); registerPostProcessor(Object.class, new MethodInvokerPostProcessor(compositeExclusionStrategy)); } if(enableExclusionByValueStrategies) { builder.registerTypeAdapterFactory(new ExcludeByValueTypeAdapterFactory(fieldInspector, factory)); } for(Class clazz: orderedClasses){ ClassConfig config = classConfigMap.get(clazz); if(config.getTypeSelector() != null) { builder.registerTypeAdapterFactory(new TypeSelectorTypeAdapterFactory(config, alreadyResolvedTypeTokensRegistry)); } builder.registerTypeAdapterFactory(new HooksTypeAdapterFactory(config)); } for(Map.Entry enumDefault: enumDefaultValues.entrySet()) { builder.registerTypeAdapterFactory(new EnumDefaultValueTypeAdapterFactory(enumDefault.getKey(), enumDefault.getValue())); } if(dateSerializationPolicy != null){ builder.registerTypeAdapter(Date.class, dateSerializationPolicy.createTypeAdapter(serializeTimeZone)); } builder.registerTypeAdapterFactory(new SimpleIterableTypeAdapterFactory()); builder.registerTypeAdapterFactory(new WrapTypeAdapterFactory(wrappedClasses)); return builder; } /** * Returns a new {@link Gson} instance * @return */ public Gson createGson(){ return createGsonBuilder().create(); } }