Solon v3.6.2

实体序列化器 EntitySerializer

</> markdown

前置参考:

1、接口声明

package org.noear.solon.serialization;

import org.noear.solon.core.handle.Context;
import org.noear.solon.core.serialize.Serializer;
import org.noear.solon.lang.Nullable;

import java.io.IOException;
import java.lang.reflect.Type;

/**
 * 通用实体序列化器(与 EntityConverter 相互对应)
 */
public interface EntitySerializer<T> extends Serializer<T> {
    /**
     * 匹配
     *
     * @param ctx  上下文
     * @param mime
     */
    boolean matched(Context ctx, String mime);

    /**
     * 媒体类型
     */
    String mimeType();

    /**
     * 必须要 body
     */
    default boolean bodyRequired() {
        return false;
    }

    /**
     * 序列化到
     *
     * @param ctx  请求上下文
     * @param data 数据
     */
    void serializeToBody(Context ctx, Object data) throws IOException;

    /**
     * 反序列化从
     *
     * @param ctx    请求上下文
     * @param toType 目标类型
     * @since 3.0
     */
    Object deserializeFromBody(Context ctx, @Nullable Type toType) throws IOException;

    /**
     * 反序列化从
     *
     * @param ctx 请求上下文
     */
    default Object deserializeFromBody(Context ctx) throws IOException {
        return deserializeFromBody(ctx, null);
    }
}

扩展接口 EntityStringSerializer :

public interface EntityStringSerializer extends EntitySerializer<String> {
    /**
     * 添加数据转换器(用于简单场景)
     */
    <T> void addEncoder(Class<T> clz, Converter<T, Object> converter);
}

2、定制参考1

package org.noear.solon.serialization.abc;

import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.ModelAndView;
import org.noear.solon.core.util.ClassUtil;
import org.noear.solon.lang.Nullable;
import org.noear.solon.serialization.EntitySerializer;
import org.noear.solon.serialization.abc.io.AbcSerializable;

import java.io.IOException;
import java.lang.reflect.Type;

public class AbcBytesSerializer implements EntitySerializer<byte[]> {
    private static final String label = "application/abc";
    private static final AbcBytesSerializer _default = new AbcBytesSerializer();

    /**
     * 默认实例
     */
    public static AbcBytesSerializer getDefault() {
        return _default;
    }


    @Override
    public String mimeType() {
        return label;
    }

    @Override
    public Class<byte[]> dataType() {
        return byte[].class;
    }

    @Override
    public boolean bodyRequired() {
        return true;
    }

    /**
     * 序列化器名字
     */
    @Override
    public String name() {
        return "abc-bytes";
    }

    @Override
    public byte[] serialize(Object fromObj) throws IOException {
        if (fromObj instanceof AbcSerializable) {
            AbcSerializable bs = ((AbcSerializable) fromObj);
            Object out = bs.serializeFactory().createOutput();
            bs.serializeWrite(out);
            return bs.serializeFactory().extractBytes(out);
        } else {
            throw new IllegalStateException("The parameter 'fromObj' is not of AbcSerializable");
        }
    }

    @Override
    public Object deserialize(byte[] data, Type toType) throws IOException {
        if (toType instanceof Class<?>) {
            if (AbcSerializable.class.isAssignableFrom((Class<?>) toType)) {
                AbcSerializable tmp = ClassUtil.newInstance((Class<?>) toType);
                Object in = tmp.serializeFactory().createInput(data);
                tmp.serializeRead(in);

                return tmp;
            } else {
                throw new IllegalStateException("The parameter 'toType' is not of AbcSerializable");
            }
        } else {
            throw new IllegalStateException("The parameter 'toType' is not Class");
        }
    }

    /// ////////////

    @Override
    public boolean matched(Context ctx, String mime) {
        if (mime == null) {
            return false;
        } else {
            return mime.startsWith(label);
        }
    }

    @Override
    public void serializeToBody(Context ctx, Object data) throws IOException {
        //如果没有设置过,用默认的 //如 ndjson,sse 或故意改变 mime(可由外部控制)
        if (ctx.contentTypeNew() == null) {
            ctx.contentType(this.mimeType());
        }

        if (data instanceof ModelAndView) {
            ctx.output(serialize(((ModelAndView) data).model()));
        } else {
            ctx.output(serialize(data));
        }
    }

    @Override
    public Object deserializeFromBody(Context ctx, @Nullable Type bodyType) throws IOException {
        return deserialize(ctx.bodyAsBytes(), bodyType);
    }
}

3、定制参考2

package org.noear.solon.serialization.fastjson2;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.reader.ObjectReaderProvider;
import com.alibaba.fastjson2.writer.ObjectWriter;
import com.alibaba.fastjson2.writer.ObjectWriterProvider;
import org.noear.solon.Utils;
import org.noear.solon.core.convert.Converter;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.ModelAndView;
import org.noear.solon.core.util.MimeType;
import org.noear.solon.lang.Nullable;
import org.noear.solon.serialization.EntityStringSerializer;
import org.noear.solon.serialization.prop.JsonProps;
import org.noear.solon.serialization.prop.JsonPropsUtil2;

import java.io.IOException;
import java.lang.reflect.Type;

/**
 * Fastjson2 字符串序列化
 */
public class Fastjson2StringSerializer implements EntityStringSerializer {
    private static final String label = "/json";
    private static final Fastjson2StringSerializer _default = new Fastjson2StringSerializer();

    /**
     * 默认实例
     */
    public static Fastjson2StringSerializer getDefault() {
        return _default;
    }

    private Fastjson2Decl<JSONWriter.Context, JSONWriter.Feature> serializeConfig;
    private Fastjson2Decl<JSONReader.Context, JSONReader.Feature> deserializeConfig;

    public Fastjson2StringSerializer(JsonProps jsonProps) {
        loadJsonProps(jsonProps);
    }

    public Fastjson2StringSerializer() {

    }

    /**
     * 获取序列化配置
     */
    public Fastjson2Decl<JSONWriter.Context, JSONWriter.Feature> getSerializeConfig() {
        if (serializeConfig == null) {
            serializeConfig = new Fastjson2Decl<>(new JSONWriter.Context(new ObjectWriterProvider()));
        }

        return serializeConfig;
    }

    /**
     * 获取反序列化配置
     */
    public Fastjson2Decl<JSONReader.Context, JSONReader.Feature> getDeserializeConfig() {
        if (deserializeConfig == null) {
            deserializeConfig = new Fastjson2Decl<>(new JSONReader.Context(new ObjectReaderProvider()));
        }
        return deserializeConfig;
    }

    /**
     * 内容类型
     */
    @Override
    public String mimeType() {
        return "application/json";
    }

    /**
     * 数据类型
     *
     */
    @Override
    public Class<String> dataType() {
        return String.class;
    }

    /**
     * 是否匹配
     *
     * @param ctx  请求上下文
     * @param mime 内容类型
     */
    @Override
    public boolean matched(Context ctx, String mime) {
        if (mime == null) {
            return false;
        } else {
            return mime.contains(label) || mime.startsWith(MimeType.APPLICATION_X_NDJSON_VALUE);
        }
    }

    /**
     * 序列化器名字
     */
    @Override
    public String name() {
        return "fastjson2-json";
    }

    /**
     * 序列化
     *
     * @param obj 对象
     */
    @Override
    public String serialize(Object obj) throws IOException {
        return JSON.toJSONString(obj, getSerializeConfig().getContext());
    }

    /**
     * 反序列化
     *
     * @param data   数据
     * @param toType 目标类型
     */
    @Override
    public Object deserialize(String data, Type toType) throws IOException {
        if (toType == null) {
            return JSON.parse(data, getDeserializeConfig().getContext());
        } else {
            return JSON.parseObject(data, toType, getDeserializeConfig().getContext());
        }
    }

    /**
     * 序列化主体
     *
     * @param ctx  请求上下文
     * @param data 数据
     */
    @Override
    public void serializeToBody(Context ctx, Object data) throws IOException {
        //如果没有设置过,用默认的 //如 ndjson,sse 或故意改变 mime(可由外部控制)
        if (ctx.contentTypeNew() == null) {
            ctx.contentType(this.mimeType());
        }

        if (data instanceof ModelAndView) {
            ctx.output(serialize(((ModelAndView) data).model()));
        } else {
            ctx.output(serialize(data));
        }
    }

    /**
     * 反序列化主体
     *
     * @param ctx 请求上下文
     */
    @Override
    public Object deserializeFromBody(Context ctx, @Nullable Type bodyType) throws IOException {
        String data = ctx.bodyNew();

        if (Utils.isNotEmpty(data)) {
            return JSON.parse(data, getDeserializeConfig().getContext());
        } else {
            return null;
        }
    }

    /**
     * 添加编码器
     *
     * @param clz     类型
     * @param encoder 编码器
     */
    public <T> void addEncoder(Class<T> clz, ObjectWriter encoder) {
        getSerializeConfig().getContext().getProvider().register(clz, encoder);
    }

    /**
     * 添加转换器(编码器的简化版)
     *
     * @param clz       类型
     * @param converter 转换器
     */
    @Override
    public <T> void addEncoder(Class<T> clz, Converter<T, Object> converter) {
        addEncoder(clz, (out, obj, fieldName, fieldType, features) -> {
            Object val = converter.convert((T) obj);
            if (val == null) {
                out.writeNull();
            } else if (val instanceof String) {
                out.writeString((String) val);
            } else if (val instanceof Number) {
                if (val instanceof Long) {
                    out.writeInt64(((Number) val).longValue());
                } else if (val instanceof Integer) {
                    out.writeInt32(((Number) val).intValue());
                } else if (val instanceof Float) {
                    out.writeDouble(((Number) val).floatValue());
                } else {
                    out.writeDouble(((Number) val).doubleValue());
                }
            } else {
                throw new IllegalArgumentException("The result type of the converter is not supported: " + val.getClass().getName());
            }
        });
    }


    protected void loadJsonProps(JsonProps jsonProps) {
        if (jsonProps != null) {
            if (jsonProps.dateAsTicks) {
                jsonProps.dateAsTicks = false;
                getSerializeConfig().getContext().setDateFormat("millis");
            }

            if (Utils.isNotEmpty(jsonProps.dateAsFormat)) {
                //这个方案,可以支持全局配置,且个性注解不会失效;//用编码器会让个性注解失效
                getSerializeConfig().getContext().setDateFormat(jsonProps.dateAsFormat);
            }

            //JsonPropsUtil.dateAsFormat(this, jsonProps);
            JsonPropsUtil2.dateAsTicks(this, jsonProps);
            JsonPropsUtil2.boolAsInt(this, jsonProps);

            boolean writeNulls = jsonProps.nullAsWriteable ||
                    jsonProps.nullNumberAsZero ||
                    jsonProps.nullArrayAsEmpty ||
                    jsonProps.nullBoolAsFalse ||
                    jsonProps.nullStringAsEmpty;

            if (jsonProps.nullStringAsEmpty) {
                getSerializeConfig().addFeatures(JSONWriter.Feature.WriteNullStringAsEmpty);
            }

            if (jsonProps.nullBoolAsFalse) {
                getSerializeConfig().addFeatures(JSONWriter.Feature.WriteNullBooleanAsFalse);
            }

            if (jsonProps.nullNumberAsZero) {
                getSerializeConfig().addFeatures(JSONWriter.Feature.WriteNullNumberAsZero);
            }

            if (jsonProps.boolAsInt) {
                getSerializeConfig().addFeatures(JSONWriter.Feature.WriteBooleanAsNumber);
            }

            if (jsonProps.longAsString) {
                getSerializeConfig().addFeatures(JSONWriter.Feature.WriteLongAsString);
            }

            if (jsonProps.nullArrayAsEmpty) {
                getSerializeConfig().addFeatures(JSONWriter.Feature.WriteNullListAsEmpty);
            }

            if (jsonProps.enumAsName) {
                getSerializeConfig().addFeatures(JSONWriter.Feature.WriteEnumsUsingName);
            }

            if (writeNulls) {
                getSerializeConfig().addFeatures(JSONWriter.Feature.WriteNulls);
            }
        }
    }
}