Package com.esotericsoftware.kryo.serializers

Source Code of com.esotericsoftware.kryo.serializers.TaggedFieldSerializer$TaggedCachedField

package com.esotericsoftware.kryo.serializers;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.Registration;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;

import static com.esotericsoftware.minlog.Log.*;

/** Serializes objects using direct field assignment for fields that have been {@link Tag tagged}. Fields without the {@link Tag}
* annotation are not serialized. New tagged fields can be added without invalidating previously serialized bytes. If any tagged
* field is removed, previously serialized bytes are invalidated. Instead of removing fields, apply the {@link Deprecated}
* annotation and they will not be serialized. If fields are public, bytecode generation will be used instead of reflection.
* @author Nathan Sweet <misc@n4te.com> */
public class TaggedFieldSerializer<T> extends FieldSerializer<T> {
  public TaggedFieldSerializer (Kryo kryo, Class type) {
    super(kryo, type);
  }

  protected CachedField newCachedField (Field field) {
    if (field.getAnnotation(Deprecated.class) != null) return null;
    Tag tag = field.getAnnotation(Tag.class);
    if (tag == null) return null;
    return new TaggedCachedField(field, tag.value());
  }

  public void write (Kryo kryo, Output output, T object) {
    CachedField[] fields = getFields();
    output.writeInt(fields.length, true);
    for (int i = 0, n = fields.length; i < n; i++) {
      CachedField cachedField = fields[i];
      try {
        if (TRACE) trace("kryo", "Write field: " + cachedField + " (" + object.getClass().getName() + ")");

        output.writeInt(((TaggedCachedField)fields[i]).tag, true);

        Object value = cachedField.get(object);

        Serializer serializer = cachedField.serializer;
        if (cachedField.valueClass == null) {
          if (value == null) {
            kryo.writeClass(output, null);
            continue;
          }
          Registration registration = kryo.writeClass(output, value.getClass());
          if (serializer == null) serializer = registration.getSerializer();
          if (cachedField.generics != null) serializer.setGenerics(kryo, cachedField.generics);
          kryo.writeObject(output, value, serializer);
        } else {
          if (serializer == null) cachedField.serializer = serializer = kryo.getSerializer(cachedField.valueClass);
          if (cachedField.generics != null) serializer.setGenerics(kryo, cachedField.generics);
          if (cachedField.canBeNull)
            kryo.writeObjectOrNull(output, value, serializer);
          else {
            if (value == null) {
              throw new KryoException("Field value is null but canBeNull is false: " + cachedField + " ("
                + object.getClass().getName() + ")");
            }
            kryo.writeObject(output, value, serializer);
          }
        }
      } catch (IllegalAccessException ex) {
        throw new KryoException("Error accessing field: " + cachedField + " (" + object.getClass().getName() + ")", ex);
      } catch (KryoException ex) {
        ex.addTrace(cachedField + " (" + object.getClass().getName() + ")");
        throw ex;
      } catch (RuntimeException runtimeEx) {
        KryoException ex = new KryoException(runtimeEx);
        ex.addTrace(cachedField + " (" + object.getClass().getName() + ")");
        throw ex;
      }
    }
  }

  public T read (Kryo kryo, Input input, Class<T> type) {
    T object = kryo.newInstance(type);
    kryo.reference(object);
    CachedField[] fields = getFields();
    int fieldCount = input.readInt(true);
    for (int i = 0, n = fieldCount; i < n; i++) {
      int tag = input.readInt(true);

      CachedField cachedField = null;
      for (int ii = 0, nn = fields.length; ii < nn; ii++) {
        TaggedCachedField f = (TaggedCachedField)fields[ii];
        if (f.tag == tag) {
          cachedField = f;
          break;
        }
      }
      if (cachedField == null) throw new KryoException("Unknown field tag: " + tag + " (" + getType().getName() + ")");

      try {
        if (TRACE) trace("kryo", "Read field: " + cachedField + " (" + getType().getName() + ")");

        Object value;

        Class concreteType = cachedField.valueClass;
        Serializer serializer = cachedField.serializer;
        if (concreteType == null) {
          Registration registration = kryo.readClass(input);
          if (registration == null)
            value = null;
          else {
            if (serializer == null) serializer = registration.getSerializer();
            if (cachedField.generics != null) serializer.setGenerics(kryo, cachedField.generics);
            value = kryo.readObject(input, registration.getType(), serializer);
          }
        } else {
          if (serializer == null) cachedField.serializer = serializer = kryo.getSerializer(concreteType);
          if (cachedField.generics != null) serializer.setGenerics(kryo, cachedField.generics);
          if (cachedField.canBeNull)
            value = kryo.readObjectOrNull(input, concreteType, serializer);
          else
            value = kryo.readObject(input, concreteType, serializer);
        }

        cachedField.set(object, value);
      } catch (IllegalAccessException ex) {
        throw new KryoException("Error accessing field: " + cachedField + " (" + getType().getName() + ")", ex);
      } catch (KryoException ex) {
        ex.addTrace(cachedField + " (" + getType().getName() + ")");
        throw ex;
      } catch (RuntimeException runtimeEx) {
        KryoException ex = new KryoException(runtimeEx);
        ex.addTrace(cachedField + " (" + getType().getName() + ")");
        throw ex;
      }
    }
    return object;
  }

  private class TaggedCachedField extends CachedField {
    final int tag;

    TaggedCachedField (Field field, int tag) {
      super(field);
      this.tag = tag;
    }
  }

  /** If true, this field will not be serialized. */
  @Retention(RetentionPolicy.RUNTIME)
  @Target(ElementType.FIELD)
  public @interface Tag {
    int value();
  }
}
TOP

Related Classes of com.esotericsoftware.kryo.serializers.TaggedFieldSerializer$TaggedCachedField

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.