Fastjson2EntityConverter.java

package com.alibaba.fastjson2.support.solon;

import com.alibaba.fastjson2.*;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.util.Assert;
import org.noear.solon.core.util.LazyReference;
import org.noear.solon.core.wrap.MethodWrap;
import org.noear.solon.core.wrap.ParamWrap;
import org.noear.solon.serialization.AbstractStringEntityConverter;
import org.noear.solon.serialization.SerializerNames;

import java.util.Collection;
import java.util.List;

/**
 * Fastjson2 EntityConverter
 *
 * @author noear
 * @since 3.6
 */
public class Fastjson2EntityConverter
        extends AbstractStringEntityConverter<Fastjson2StringSerializer> {
    public Fastjson2EntityConverter(Fastjson2StringSerializer serializer) {
        super(serializer);

        serializer.getDeserializeConfig().addFeatures(JSONReader.Feature.ErrorOnEnumNotMatch);
        serializer.getSerializeConfig().addFeatures(JSONWriter.Feature.BrowserCompatible);
    }

    /**
     * Suffix or name mapping
     */
    @Override
    public String[] mappings() {
        return new String[]{SerializerNames.AT_JSON};
    }

    /**
     * Change body
     *
     * @param ctx Handling context
     * @param mWrap Method wrappers
     */
    @Override
    protected Object changeBody(Context ctx, MethodWrap mWrap) throws Exception {
        return serializer.deserializeFromBody(ctx);
    }

    /**
     * Change value
     *
     * @param ctx Handling context
     * @param p Parameter wrappers
     * @param pi Parameter index
     * @param pt Parameter type
     * @param bodyRef BodyValue Reference
     */
    @Override
    protected Object changeValue(Context ctx, ParamWrap p, int pi, Class<?> pt, LazyReference bodyRef) throws Throwable {
        if (p.spec().isRequiredPath() || p.spec().isRequiredCookie() || p.spec().isRequiredHeader()) {
            //If path���cookie, header?
            return super.changeValue(ctx, p, pi, pt, bodyRef);
        }

        if (p.spec().isRequiredBody() == false && ctx.paramMap().containsKey(p.spec().getName())) {
            //If path���queryString?
            return super.changeValue(ctx, p, pi, pt, bodyRef);
        }

        Object bodyObj = bodyRef.get();

        if (bodyObj == null) {
            return super.changeValue(ctx, p, pi, pt, bodyRef);
        }

        if (bodyObj instanceof JSONObject) {
            JSONObject tmp = (JSONObject) bodyObj;

            if (p.spec().isRequiredBody() == false) {
                //
                //If there is no body requirement; Try to find by attribute
                //
                if (tmp.containsKey(p.spec().getName())) {
                    //Supports conversions of generic types
                    if (p.spec().isGenericType()) {
                        return tmp.getObject(p.spec().getName(), p.getGenericType());
                    } else {
                        return tmp.getObject(p.spec().getName(), pt);
                    }
                }
            }

            //Try the body conversion
            if (pt.isPrimitive() || pt.getTypeName().startsWith("java.lang.")) {
                return super.changeValue(ctx, p, pi, pt, bodyRef);
            } else {
                if (List.class.isAssignableFrom(pt)) {
                    return null;
                }

                if (pt.isArray()) {
                    return null;
                }

                //Generic transformations such as Map<T>
                if (p.spec().isGenericType()) {
                    return tmp.to(p.getGenericType());
                } else {
                    return tmp.to(pt);
                }
            }
        }

        if (bodyObj instanceof JSONArray) {
            JSONArray tmp = (JSONArray) bodyObj;
            //If the argument is a non-collection type
            if (!Collection.class.isAssignableFrom(pt)) {
                return null;
            }
            //Collection Type Conversions
            if (p.spec().isGenericType()) {
                //Transforms a collection with generics
                return tmp.to(p.getGenericType());
            } else {
                //Can be converted not only to a List but also to a Set
                return tmp.to(pt);
            }
        }

        return bodyObj;
    }

    static class Fastjson2Decl<C, F> {
        private final boolean forSerialize;
        private C context;

        public Fastjson2Decl(C context) {
            this.context = context;

            if (context instanceof JSONWriter.Context) {
                forSerialize = true;
            } else {
                forSerialize = false;
            }
        }

        /**
         * Get context
         */
        public C getContext() {
            return context;
        }

        /**
         * Reset context
         */
        public void setContext(C context) {
            Assert.notNull(context, "context can not be null");
            this.context = context;
        }

        /**
         * Set features
         */
        public void setFeatures(F... features) {
            if (forSerialize) {
                ((JSONWriter.Context) context).setFeatures(JSONFactory.getDefaultWriterFeatures());
            } else {
                ((JSONReader.Context) context).setFeatures(JSONFactory.getDefaultReaderFeatures());
            }

            addFeatures(features);
        }

        /**
         * Add features
         */
        public void addFeatures(F... features) {
            if (forSerialize) {
                //���������
                for (F f1 : features) {
                    JSONWriter.Feature feature = (JSONWriter.Feature) f1;
                    ((JSONWriter.Context) context).config(feature, true);
                }
            } else {
                for (F f1 : features) {
                    JSONReader.Feature feature = (JSONReader.Feature) f1;
                    ((JSONReader.Context) context).config(feature, true);
                }
            }
        }

        /**
         * Remove features
         */
        public void removeFeatures(F... features) {
            if (forSerialize) {
                //���������
                for (F f1 : features) {
                    JSONWriter.Feature feature = (JSONWriter.Feature) f1;
                    ((JSONWriter.Context) context).config(feature, false);
                }
            } else {
                for (F f1 : features) {
                    JSONReader.Feature feature = (JSONReader.Feature) f1;
                    ((JSONReader.Context) context).config(feature, false);
                }
            }
        }
    }
}