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

com.jn.agileway.codec.serialization.kryo.Kryos Maven / Gradle / Ivy

Go to download

Provide an unified codec API for hession, kryo, protostuff, fst, fes, xson, cbor, jackson, json, etc....

There is a newer version: 3.1.12
Show newest version
package com.jn.agileway.codec.serialization.kryo;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Registration;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.BeanSerializer;
import com.jn.langx.Factory;
import com.jn.langx.annotation.NonNull;
import com.jn.langx.annotation.Nullable;
import com.jn.langx.text.StringTemplates;
import com.jn.langx.util.Emptys;
import com.jn.langx.util.Preconditions;
import com.jn.langx.util.collection.Collects;
import com.jn.langx.util.collection.Pipeline;
import com.jn.langx.util.concurrent.threadlocal.ThreadLocalFactory;
import com.jn.langx.util.function.Consumer;
import com.jn.langx.util.function.Consumer2;
import com.jn.langx.util.io.IOs;
import com.jn.langx.util.logging.Loggers;
import com.jn.langx.util.reflect.Reflects;
import com.jn.langx.util.reflect.type.Primitives;
import org.slf4j.Logger;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;

public class Kryos {

    private Kryos() {
    }

    private static final Logger logger = Loggers.getLogger(Kryos.class);

    private static final Map kryoCustomizerRegistry = new ConcurrentHashMap();

    public static final ThreadLocalFactory kryoFactory = new ThreadLocalFactory(new Factory() {
        @Override
        public Kryo get(Object o) {
            final Kryo kryo = new Kryo();

            kryo.setOptimizedGenerics(true);

            kryo.setReferences(true);
            kryo.setCopyReferences(false);
            // 设置为 false,等价于禁用了精确的类 serializer 查找,例如 默认有 Map接口的 Serializer,没有HashMap的,
            // 如果类是个hashMap,如果设置为true,即精确查找的话,会因为找不到合适的Serializer而导致序列化失败,
            kryo.setRegistrationRequired(false);
            Collects.forEach(kryoCustomizerRegistry, new Consumer2() {
                @Override
                public void accept(String name, KryoCustomizer customizer) {
                    try {
                        customizer.customize(kryo);
                    } catch (Throwable ex) {
                        if (ex instanceof NoClassDefFoundError || ex instanceof ClassNotFoundException) {
                            logger.error("Error occur when register kryo serializers for {}, may be you should append de.javakaffee:kryo-serializers.jar to the classpath", name);
                        } else {
                            logger.error("Error occur when register kryo customizer  for {}", name);
                        }
                    }
                }
            });

            return kryo;
        }
    });

    public static  byte[] serialize(T o) {
        return serialize(kryoFactory, o);
    }

    public static  void serialize(T o, OutputStream outputStream) {
        serialize(kryoFactory, o, outputStream);
    }

    public static  byte[] serialize(Factory kryoFactory, T o) {
        if (o == null) {
            return null;
        }
        Preconditions.checkNotNull(kryoFactory, "the kryo factory is null");
        Kryo kryo = kryoFactory.get(null);
        return serialize(kryo, o);
    }


    public static  void serialize(@NonNull Factory kryoFactory, @Nullable T o, @NonNull OutputStream outputStream) {
        if (o == null) {
            return;
        }
        Preconditions.checkNotNull(kryoFactory, "the kryo factory is null");
        Kryo kryo = kryoFactory.get(null);
        serialize(kryo, o, outputStream);
    }

    public static  byte[] serialize(@NonNull Kryo kryo, @Nullable T o) {
        if (o == null) {
            return null;
        }
        ByteArrayOutputStream bao = new ByteArrayOutputStream();
        try {
            serialize(kryo, o, bao);
            return bao.toByteArray();
        } finally {
            IOs.close(bao);
        }
    }


    public static  void serialize(@NonNull Kryo kryo, @Nullable T o, @NonNull OutputStream outputStream) {
        if (o == null) {
            return;
        }
        Preconditions.checkNotNull(kryo, "the kryo is null");
        Output output = null;
        try {
            output = new Output(outputStream);
            if (!Primitives.isPrimitiveOrPrimitiveWrapperType(o.getClass())) {
                kryo.register(o.getClass(), new BeanSerializer(kryo, o.getClass()));
            }
            kryo.writeClassAndObject(output, o);
            output.flush();
        } finally {
            IOs.close(output);
        }
    }

    public static  T deserialize(byte[] bytes) throws IOException {
        return deserialize(kryoFactory, bytes);
    }

    public static  T deserialize(@Nullable byte[] bytes, @Nullable Class targetType) throws IOException {
        return deserialize(getKryoFactory(null), bytes, targetType);
    }

    public static  T deserialize(Factory kryoFactory, byte[] bytes) throws IOException {
        return deserialize(getKryoFactory(kryoFactory), bytes, null);
    }


    public static  T deserialize(@Nullable Factory kryoFactory, @Nullable byte[] bytes, @Nullable Class targetType) throws IOException {
        if (Emptys.isEmpty(bytes)) {
            return null;
        }
        return deserialize(getKryoFactory(kryoFactory).get(null), bytes, targetType);
    }


    public static  T deserialize(Kryo kryo, byte[] bytes) throws IOException {
        return deserialize(kryo, bytes, null);
    }


    public static  T deserialize(Kryo kryo, byte[] bytes, Class targetType) throws IOException {
        if (Emptys.isEmpty(bytes)) {
            return null;
        }
        Input input = null;
        try {
            ByteArrayInputStream bai = new ByteArrayInputStream(bytes);
            input = new Input(bai);
            if (targetType != null) {
                autoRegister(kryo, targetType);
            }
            Class actualClass = null;

            // 读类
            Registration actualTypeRegistration = kryo.readClass(input);

            if (input.available() < 1) {
                return null;
            }

            if (actualTypeRegistration != null) {
                actualClass = actualTypeRegistration.getType();
            }
            // 读数据
            if (actualClass != null && targetType != null) {
                if (Reflects.isSubClassOrEquals(targetType, actualClass)) {
                    if (actualClass != targetType) {
                        autoRegister(kryo, actualClass);
                    }
                    return (T) kryo.readObjectOrNull(input, actualClass);
                } else {
                    throw new ClassCastException(StringTemplates.formatWithPlaceholder("class {} is not cast to {}", Reflects.getFQNClassName(actualClass), Reflects.getFQNClassName(targetType)));
                }
            } else {
                if (targetType == null) {
                    return (T) kryo.readObjectOrNull(input, actualClass);
                } else {
                    return kryo.readObjectOrNull(input, targetType);
                }
            }
        } finally {
            IOs.close(input);
        }
    }

    public static Factory getKryoFactory(@Nullable Factory kryoFactory) {
        return kryoFactory == null ? Kryos.kryoFactory : kryoFactory;
    }

    public static void autoRegister(Kryo kryo, Class type) {
        if (!Primitives.isPrimitiveOrPrimitiveWrapperType(type)) {
            if ((kryo.getRegistration(type) != null && kryo.getSerializer(type) != null) || kryo.getDefaultSerializer(type) != null) {
                kryo.register(type, new BeanSerializer(kryo, type));
            }
        }
    }

    static {
        ServiceLoader loader = ServiceLoader.load(KryoCustomizer.class);
        Pipeline.of(loader).forEach(new Consumer() {
            @Override
            public void accept(KryoCustomizer kryoCustomizer) {
                kryoCustomizerRegistry.put(kryoCustomizer.getName(), kryoCustomizer);
                logger.info("Load the kryo serializers for {}", kryoCustomizer.getName());
            }
        });
    }

    public static void registerCustomizer(String name, KryoCustomizer customizer) {
        kryoCustomizerRegistry.put(name, customizer);
    }

    public static KryoCustomizer getCustomizer(String name) {
        return kryoCustomizerRegistry.get(name);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy