View Javadoc
1   /*
2    *    Copyright 2015-2023 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       https://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.mybatis.caches.redis;
17  
18  import com.esotericsoftware.kryo.kryo5.Kryo;
19  import com.esotericsoftware.kryo.kryo5.io.Input;
20  import com.esotericsoftware.kryo.kryo5.io.Output;
21  
22  import java.util.Arrays;
23  import java.util.Set;
24  import java.util.concurrent.ConcurrentHashMap;
25  
26  /**
27   * SerializeUtil with Kryo, which is faster and less space consuming.
28   *
29   * @author Lei Jiang(ladd.cn@gmail.com)
30   */
31  public enum KryoSerializer implements Serializer {
32    // Enum singleton, which is preferred approach since Java 1.5
33    INSTANCE;
34  
35    /**
36     * kryo is thread-unsafe, use ThreadLocal.
37     */
38    private ThreadLocal<Kryo> kryos = ThreadLocal.withInitial(Kryo::new);
39  
40    /**
41     * Classes which can not resolved by default kryo serializer, which occurs very
42     * rare(https://github.com/EsotericSoftware/kryo#using-standard-java-serialization) For these classes, we will use
43     * fallbackSerializer(use JDKSerializer now) to resolve.
44     */
45    private Set<Class<?>> unnormalClassSet;
46  
47    /**
48     * Hash codes of unnormal bytes which can not resolved by default kryo serializer, which will be resolved by
49     * fallbackSerializer
50     */
51    private Set<Integer> unnormalBytesHashCodeSet;
52    private Serializer fallbackSerializer;
53  
54    private KryoSerializer() {
55      unnormalClassSet = ConcurrentHashMap.newKeySet();
56      unnormalBytesHashCodeSet = ConcurrentHashMap.newKeySet();
57      fallbackSerializer = JDKSerializer.INSTANCE;// use JDKSerializer as fallback
58    }
59  
60    @Override
61    public byte[] serialize(Object object) {
62      if (unnormalClassSet.contains(object.getClass())) {
63        // For unnormal class
64        return fallbackSerializer.serialize(object);
65      }
66  
67      /**
68       * In the following cases: 1. This class occurs for the first time. 2. This class have occurred and can be resolved
69       * by default kryo serializer
70       */
71      try (Output output = new Output(200, -1)) {
72        kryos.get().writeClassAndObject(output, object);
73        return output.toBytes();
74      } catch (Exception e) {
75        // For unnormal class occurred for the first time, exception will be thrown
76        unnormalClassSet.add(object.getClass());
77        return fallbackSerializer.serialize(object);// use fallback Serializer to resolve
78      }
79    }
80  
81    @Override
82    public Object unserialize(byte[] bytes) {
83      if (bytes == null) {
84        return null;
85      }
86      int hashCode = Arrays.hashCode(bytes);
87      if (unnormalBytesHashCodeSet.contains(hashCode)) {
88        // For unnormal bytes
89        return fallbackSerializer.unserialize(bytes);
90      }
91  
92      /**
93       * In the following cases: 1. This bytes occurs for the first time. 2. This bytes have occurred and can be resolved
94       * by default kryo serializer
95       */
96      try (Input input = new Input()) {
97        input.setBuffer(bytes);
98        return kryos.get().readClassAndObject(input);
99      } catch (Exception e) {
100       // For unnormal bytes occurred for the first time, exception will be thrown
101       unnormalBytesHashCodeSet.add(hashCode);
102       return fallbackSerializer.unserialize(bytes);// use fallback Serializer to resolve
103     }
104   }
105 
106 }