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

com.esotericsoftware.kryo.serializers.MapSerializer Maven / Gradle / Ivy

Go to download

Easy Redis Java client and Real-Time Data Platform. Valkey compatible. Sync/Async/RxJava3/Reactive API. Client side caching. Over 50 Redis based Java objects and services: JCache API, Apache Tomcat, Hibernate, Spring, Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Scheduler, RPC

There is a newer version: 3.40.2
Show newest version
/* Copyright (c) 2008-2023, Nathan Sweet
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
 * conditions are met:
 * 
 * - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided with the distribution.
 * - Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

package com.esotericsoftware.kryo.serializers;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.SerializerFactory;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.util.Generics.GenericType;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

/** Serializes objects that implement the {@link Map} interface.
 * 

* With the default constructor, a map requires a 1-3 byte header and an extra 4 bytes is written for each key/value pair. * @author Nathan Sweet */ public class MapSerializer extends Serializer { private Class keyClass, valueClass; private Serializer keySerializer, valueSerializer; private boolean keysCanBeNull = true, valuesCanBeNull = true; public MapSerializer () { setAcceptsNull(true); } /** @param keysCanBeNull False if all keys are not null. This saves 1 byte per key if keyClass is set. True if it is not known * (default). */ public void setKeysCanBeNull (boolean keysCanBeNull) { this.keysCanBeNull = keysCanBeNull; } /** The concrete class of the keys for this map, or null if it is not known. This saves 1-2 bytes. Only set to a non-null value * if the keys for this map are known to be of the specified type (or null). */ public void setKeyClass (Class keyClass) { this.keyClass = keyClass; } public Class getKeyClass () { return keyClass; } /** Sets both {@link #setKeyClass(Class)} and {@link #setKeySerializer(Serializer)}. */ public void setKeyClass (Class keyClass, Serializer keySerializer) { this.keyClass = keyClass; this.keySerializer = keySerializer; } /** The serializer to be used for the keys in this map, or null to use the serializer registered with {@link Kryo} for the * type. Default is null. */ public void setKeySerializer (Serializer keySerializer) { this.keySerializer = keySerializer; } public Serializer getKeySerializer () { return this.keySerializer; } /** The concrete class of the values for this map, or null if it is not known. This saves 1-2 bytes. Only set to a non-null * value if the values for this map are known to be of the specified type (or null). */ public void setValueClass (Class valueClass) { this.valueClass = valueClass; } public Class getValueClass () { return valueClass; } /** Sets both {@link #setValueClass(Class)} and {@link #setValueSerializer(Serializer)}. */ public void setValueClass (Class valueClass, Serializer valueSerializer) { this.valueClass = valueClass; this.valueSerializer = valueSerializer; } /** The serializer to be used for this field, or null to use the serializer registered with {@link Kryo} for the type. Default * is null. */ public void setValueSerializer (Serializer valueSerializer) { this.valueSerializer = valueSerializer; } public Serializer getValueSerializer () { return this.valueSerializer; } /** @param valuesCanBeNull True if values are not null. This saves 1 byte per value if keyClass is set. False if it is not * known (default). */ public void setValuesCanBeNull (boolean valuesCanBeNull) { this.valuesCanBeNull = valuesCanBeNull; } public void write (Kryo kryo, Output output, T map) { if (map == null) { output.writeByte(0); return; } int size = map.size(); if (size == 0) { output.writeByte(1); writeHeader(kryo, output, map); return; } output.writeVarInt(size + 1, true); writeHeader(kryo, output, map); Serializer keySerializer = this.keySerializer, valueSerializer = this.valueSerializer; GenericType[] genericTypes = kryo.getGenerics().nextGenericTypes(); if (genericTypes != null) { if (keySerializer == null) { Class keyType = genericTypes[0].resolve(kryo.getGenerics()); if (keyType != null && kryo.isFinal(keyType)) keySerializer = kryo.getSerializer(keyType); } if (valueSerializer == null) { Class valueType = genericTypes[1].resolve(kryo.getGenerics()); if (valueType != null && kryo.isFinal(valueType)) valueSerializer = kryo.getSerializer(valueType); } } for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) { Entry entry = (Entry)iter.next(); if (genericTypes != null) kryo.getGenerics().pushGenericType(genericTypes[0]); if (keySerializer != null) { if (keysCanBeNull) kryo.writeObjectOrNull(output, entry.getKey(), keySerializer); else kryo.writeObject(output, entry.getKey(), keySerializer); } else kryo.writeClassAndObject(output, entry.getKey()); if (genericTypes != null) kryo.getGenerics().popGenericType(); if (valueSerializer != null) { if (valuesCanBeNull) kryo.writeObjectOrNull(output, entry.getValue(), valueSerializer); else kryo.writeObject(output, entry.getValue(), valueSerializer); } else kryo.writeClassAndObject(output, entry.getValue()); } kryo.getGenerics().popGenericType(); } /** Can be overidden to write data needed for {@link #create(Kryo, Input, Class, int)}. The default implementation does * nothing. */ protected void writeHeader (Kryo kryo, Output output, T map) { } /** Used by {@link #read(Kryo, Input, Class)} to create the new object. This can be overridden to customize object creation, eg * to call a constructor with arguments. The default implementation uses {@link Kryo#newInstance(Class)} with a special case * for HashMap. */ protected T create (Kryo kryo, Input input, Class type, int size) { if (type == HashMap.class) { if (size < 3) size++; else if (size < 1073741824) // Max POT. size = (int)(size / 0.75f + 1); // 0.75 is the default load factor. return (T)new HashMap(size); } return kryo.newInstance(type); } public T read (Kryo kryo, Input input, Class type) { int length = input.readVarInt(true); if (length == 0) return null; length--; T map = create(kryo, input, type, length); kryo.reference(map); if (length == 0) return map; Class keyClass = this.keyClass; Class valueClass = this.valueClass; Serializer keySerializer = this.keySerializer, valueSerializer = this.valueSerializer; GenericType[] genericTypes = kryo.getGenerics().nextGenericTypes(); if (genericTypes != null) { if (keySerializer == null) { Class genericClass = genericTypes[0].resolve(kryo.getGenerics()); if (genericClass != null && kryo.isFinal(genericClass)) { keySerializer = kryo.getSerializer(genericClass); keyClass = genericClass; } } if (valueSerializer == null) { Class genericClass = genericTypes[1].resolve(kryo.getGenerics()); if (genericClass != null && kryo.isFinal(genericClass)) { valueSerializer = kryo.getSerializer(genericClass); valueClass = genericClass; } } } for (int i = 0; i < length; i++) { Object key; if (genericTypes != null) kryo.getGenerics().pushGenericType(genericTypes[0]); if (keySerializer != null) { if (keysCanBeNull) key = kryo.readObjectOrNull(input, keyClass, keySerializer); else key = kryo.readObject(input, keyClass, keySerializer); } else key = kryo.readClassAndObject(input); if (genericTypes != null) kryo.getGenerics().popGenericType(); Object value; if (valueSerializer != null) { if (valuesCanBeNull) value = kryo.readObjectOrNull(input, valueClass, valueSerializer); else value = kryo.readObject(input, valueClass, valueSerializer); } else value = kryo.readClassAndObject(input); map.put(key, value); } kryo.getGenerics().popGenericType(); return map; } protected T createCopy (Kryo kryo, T original) { return (T)kryo.newInstance(original.getClass()); } public T copy (Kryo kryo, T original) { T copy = createCopy(kryo, original); for (Iterator iter = original.entrySet().iterator(); iter.hasNext();) { Entry entry = (Entry)iter.next(); copy.put(kryo.copy(entry.getKey()), kryo.copy(entry.getValue())); } return copy; } /** Annotates a {@link Map} field with {@link MapSerializer} settings for {@link FieldSerializer}. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface BindMap { /** @see MapSerializer#setKeyClass(Class) */ Class keyClass() default Object.class; /** The key serializer class, which will be created using the {@link #keySerializerFactory()}. Can be omitted if the * serializer factory knows what type of serializer to create. * @see MapSerializer#setKeySerializer(Serializer) */ Class keySerializer() default Serializer.class; /** The factory used to create the key serializer. */ Class keySerializerFactory() default SerializerFactory.class; /** @see MapSerializer#setValueClass(Class) */ Class valueClass() default Object.class; /** The value serializer class, which will be created using the {@link #valueSerializerFactory()}. Can be omitted if the * serializer factory knows what type of serializer to create. * @see MapSerializer#setValueSerializer(Serializer) */ Class valueSerializer() default Serializer.class; /** The factory used to create the value serializer. */ Class valueSerializerFactory() default SerializerFactory.class; /** Indicates if keys can be null * @return true, if keys can be null */ boolean keysCanBeNull() default true; /** Indicates if values can be null * @return true, if values can be null */ boolean valuesCanBeNull() default true; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy