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

com.jn.easyjson.gson.GsonJSONBuilder Maven / Gradle / Ivy

There is a newer version: 3.2.26
Show newest version
/*
 * Copyright 2019 the original author or authors.
 *
 * Licensed under the Apache, 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.gnu.org/licenses/lgpl-3.0.html
 *
 * 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.jn.easyjson.gson;

import com.google.gson.FieldNamingStrategy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.internal.ConstructorConstructor;
import com.google.gson.internal.bind.JsonAdapterAnnotationTypeAdapterFactory;
import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory;
import com.jn.easyjson.core.JSON;
import com.jn.easyjson.core.JSONBuilder;
import com.jn.easyjson.core.annotation.DependOn;
import com.jn.easyjson.core.bean.propertynaming.BeanPropertyNamingPolicy;
import com.jn.easyjson.core.bean.propertynaming.BeanPropertyNamingPolicyRegistry;
import com.jn.easyjson.core.bean.propertynaming.ProxyDialectNamingPolicy;
import com.jn.easyjson.core.codec.dialect.DialectIdentify;
import com.jn.easyjson.core.exclusion.Exclusion;
import com.jn.easyjson.core.exclusion.ExclusionConfiguration;
import com.jn.easyjson.gson.bean.fieldnaming.GsonFieldNamingStrategyAdapter;
import com.jn.easyjson.gson.exclusion.DelegateExclusionStrategy;
import com.jn.easyjson.gson.typeadapter.*;
import com.jn.langx.annotation.Name;
import com.jn.langx.util.Strings;
import com.jn.langx.util.collection.iter.ReverseListIterator;
import com.jn.langx.util.collection.multivalue.MultiValueMap;
import com.jn.langx.util.reflect.Reflects;
import com.jn.langx.util.struct.counter.SimpleIntegerCounter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

@Name("gson")
@DependOn("com.google.gson.Gson")
public class GsonJSONBuilder extends JSONBuilder {
    private static final Logger logger = LoggerFactory.getLogger(GsonJSONBuilder.class);

    public static final DialectIdentify GSON = new DialectIdentify();

    // 用谷歌的Gson 把集合转换为字符串,当集合中数据有特殊字符时 转换完毕 会变为类似\u0027的编码
    private boolean disableHtmlEscaping = true;

    static {
        GSON.setId("gson");
        GSON.setLibUrl(Reflects.getCodeLocation(Gson.class).toString());
    }

    public void setDisableHtmlEscaping(boolean disableHtmlEscaping) {
        this.disableHtmlEscaping = disableHtmlEscaping;
    }

    public boolean isDisableHtmlEscaping() {
        return disableHtmlEscaping;
    }

    public GsonJSONBuilder() {
        super();
        dialectIdentify(GSON);
    }

    public GsonJSONBuilder(ExclusionConfiguration exclusionConfiguration) {
        super(exclusionConfiguration);
        dialectIdentify(GSON);
    }

    @Override
    public JSON build() {
        GsonBuilder gsonBuilder = new GsonBuilder();
        // Null
        if (serializeNulls()) {
            gsonBuilder.serializeNulls();
        }

        // Boolean
        gsonBuilder.registerTypeAdapterFactory(new BooleanTypeAdapterFactory(this));
        // Number
        gsonBuilder.registerTypeAdapterFactory(new NumberTypeAdapterFactory(this));
        // Date
        gsonBuilder.registerTypeAdapterFactory(new DateTypeAdapterFactory(this));
        // Enum
        gsonBuilder.registerTypeAdapterFactory(new EnumTypeAdapterFactory(this));

        // bytes
        gsonBuilder.registerTypeAdapterFactory(new BytesTypeAdapterFactory(this));

        // calender
        gsonBuilder.registerTypeAdapterFactory(new CalendarTypeAdapterFactory(this));
        gsonBuilder.registerTypeAdapterFactory(new MultiValueMapTypeAdapterFactory());


        // pretty printing
        if (prettyFormat()) {
            gsonBuilder.setPrettyPrinting();
        }

        // 避免特殊字符转换成了类似\u0027的编码
        if (isDisableHtmlEscaping()) {
            gsonBuilder.disableHtmlEscaping();
        }

        // exclusion
        List modifiers = getExclusionConfiguration().getModifiers();
        int[] modifiers0 = new int[modifiers.size()];
        for (int i = 0; i < modifiers.size(); i++) {
            modifiers0[i] = modifiers.get(i);
        }
        gsonBuilder.excludeFieldsWithModifiers(modifiers0);
        for (Exclusion exclusion : getExclusionConfiguration().getDeserializationStrategies()) {
            gsonBuilder.addDeserializationExclusionStrategy(new DelegateExclusionStrategy(exclusion, false));
        }
        for (Exclusion exclusion : getExclusionConfiguration().getSerializationStrategies()) {
            gsonBuilder.addSerializationExclusionStrategy(new DelegateExclusionStrategy(exclusion, true));
        }
        if (getExclusionConfiguration().isSerializeInnerClasses()) {
            gsonBuilder.disableInnerClassSerialization();
        }

        if (Strings.isNotBlank(beanPropertyNamingPolicy())) {
            BeanPropertyNamingPolicy policy = BeanPropertyNamingPolicyRegistry.INSTANCE.get(beanPropertyNamingPolicy());
            if (proxyDialectIdentify() != null) {
                policy = new ProxyDialectNamingPolicy(proxyDialectIdentify(), policy);
            }
            gsonBuilder.setFieldNamingStrategy(new GsonFieldNamingStrategyAdapter(policy));
        }

        Gson gson = gsonBuilder.create();
        // replace ObjectTypeAdapter
        replaceFactories(gson);

        JSON json = new JSON();
        GsonAdapter gsonAdapter = new GsonAdapter();
        gsonAdapter.setDelegate(gson);
        gsonAdapter.setJsonBuilder(this);
        json.setJsonHandler(gsonAdapter);
        applyCustomizer(json);
        return json;
    }

    private static Field factoriesField = null;
    private static Field jsonAdapterFactoryField = null;
    private static Field constructorConstructorField = null;
    private static Field fieldNamingStrategyField = null;

    private void replaceFactories(Gson gson) {
        if (findFactoriesField()) {
            try {
                factoriesField.setAccessible(true);
                List factories = new ArrayList((List) factoriesField.get(gson));
                // 替换 ObjectTypeAdapter
                int index = -1;
                /*
                index = factories.indexOf(com.google.gson.internal.bind.ObjectTypeAdapter.FACTORY);
                if (index >= 0) {
                    // replace
                    factories.remove(index);
                    factories.add(index, ObjectTypeAdapter.FACTORY);
                }

                 */
                //
                if (jsonAdapterFactoryField != null && constructorConstructorField != null) {
                    ConstructorConstructor constructorConstructor = Reflects.getFieldValue(constructorConstructorField, gson, true, false);

                    // 替换 jsonAnnotationAdapterFactory
                    JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory = Reflects.getFieldValue(jsonAdapterFactoryField, gson, true, false);
                    EasyjsonAdapterAnnotationTypeAdapterFactory easyjsonAnnotationTypeAdapterFactory = new EasyjsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
                    if (jsonAdapterFactory != null) {
                        index = factories.indexOf(jsonAdapterFactory);
                    }
                    if (index >= 0) {
                        factories.remove(index);
                        factories.add(index, easyjsonAnnotationTypeAdapterFactory);
                        // it will fail, because a final field will not be modified
                        Reflects.setFieldValue(jsonAdapterFactoryField, gson, easyjsonAnnotationTypeAdapterFactory, true, false);
                    }

                    // 替换 reflectiveTypeAdapterFactory
                    Iterator iterator = new ReverseListIterator(factories);
                    SimpleIntegerCounter reflectiveTypeAdapterFactoryIndex = new SimpleIntegerCounter(factories.size());
                    while (iterator.hasNext()) {
                        reflectiveTypeAdapterFactoryIndex.decrement();
                        TypeAdapterFactory typeAdapterFactory = iterator.next();
                        if (typeAdapterFactory instanceof ReflectiveTypeAdapterFactory) {
                            break;
                        }
                    }
                    index = reflectiveTypeAdapterFactoryIndex.get();
                    if (index >= 0 && index < factories.size()) {
                        FieldNamingStrategy fieldNamingStrategy = Reflects.getFieldValue(fieldNamingStrategyField, gson, true, false);
                        EasyjsonReflectiveTypeAdapterFactory reflectiveTypeAdapterFactory = new EasyjsonReflectiveTypeAdapterFactory(
                                constructorConstructor,
                                fieldNamingStrategy,
                                gson.excluder(),
                                easyjsonAnnotationTypeAdapterFactory
                        );
                        factories.remove(index);
                        factories.add(reflectiveTypeAdapterFactory);
                    }
                }

                factoriesField.set(gson, factories);
            } catch (Throwable ex) {
                // ignore it
            }
        }
    }

    private static boolean findFactoriesField() {
        if (factoriesField != null) {
            return true;
        }
        factoriesField = Reflects.getDeclaredField(Gson.class, "factories");
        jsonAdapterFactoryField = Reflects.getDeclaredField(Gson.class, "jsonAdapterFactory");
        constructorConstructorField = Reflects.getDeclaredField(Gson.class, "constructorConstructor");
        fieldNamingStrategyField = Reflects.getDeclaredField(Gson.class, "fieldNamingStrategy");

        return factoriesField != null;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        GsonJSONBuilder result = new GsonJSONBuilder(this.getExclusionConfiguration());
        this.copyTo(result);
        return result;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy