com.tangosol.io.pof.PofAnnotationSerializer Maven / Gradle / Ivy
Show all versions of coherence Show documentation
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
package com.tangosol.io.pof;
import com.tangosol.io.Evolvable;
import com.tangosol.io.pof.annotation.Portable;
import com.tangosol.io.pof.annotation.PortableProperty;
import com.tangosol.io.pof.reflect.Codec;
import com.tangosol.io.pof.reflect.internal.AnnotationVisitor;
import com.tangosol.io.pof.reflect.internal.ClassMetadataBuilder;
import com.tangosol.io.pof.reflect.internal.TypeMetadata;
import com.tangosol.io.pof.reflect.internal.TypeMetadata.AttributeMetadata;
import com.tangosol.util.Binary;
import java.io.IOException;
import java.util.Iterator;
/**
* A {@link PofAnnotationSerializer} provides annotation based
* de/serialization. This serializer must be instantiated with the intended
* class which is eventually scanned for the presence of the following
* annotations.
*
* - {@link Portable}
* - {@link PortableProperty}
*
*
* This serializer supports classes iff they are annotated with the type
* level annotation; {@link Portable}. This annotation is a marker annotation
* with no children.
*
* All fields annotated with {@link PortableProperty} are explicitly
* deemed POF serializable with the option of specifying overrides to
* provide explicit behaviour such as:
*
* - explicit POF indexes
* - Custom {@link Codec} <T> to
* specify concrete implementations / customizations
*
*
* The {@link PortableProperty#value()} (POF index) can be omitted iff the
* auto-indexing feature is enabled. This is enabled by instantiating this
* class with the {@code fAutoIndex} constructor argument. This feature
* determines the index based on any explicit indexes specified and the name
* of the portable properties. Currently objects with multiple versions is
* not supported. The following illustrates the auto index algorithm:
*
* Examples on POF index
* Name Explicit Index Determined Index
* c 1 1
* a 0
* b 2
*
*
* NOTE: This implementation does support objects that implement
* Evolvable
*
* @author hr
*
* @since 3.7.1
*
* @param the user type this PofAnnotationSerializer will (de)serialize
*
* @see Portable
*/
public class PofAnnotationSerializer
implements PofSerializer
{
// ----- constructors ---------------------------------------------------
/**
* Constructs a PofAnnotationSerializer.
*
* @param nTypeId the POF type id
* @param clz type this serializer is aware of
*/
public PofAnnotationSerializer(int nTypeId, Class clz)
{
this(nTypeId, clz, false);
}
/**
* Constructs a PofAnnotationSerializer.
*
* @param nTypeId the POF type id
* @param clz type this serializer is aware of
* @param fAutoIndex turns on the auto index feature
*/
public PofAnnotationSerializer(int nTypeId, Class clz, boolean fAutoIndex)
{
if (clz == null)
{
throw new IllegalArgumentException("PofAnnotationSerializer requires a class");
}
// fail-fast
initialize(nTypeId, clz, fAutoIndex);
}
// ----- PofSerializer interface ----------------------------------------
/**
* {@inheritDoc}
*/
public void serialize(PofWriter out, Object o) throws IOException
{
// set the version identifier
boolean fEvolvable = o instanceof Evolvable;
Evolvable evolvable = null;
if (fEvolvable)
{
evolvable = (Evolvable) o;
out.setVersionId(Math.max(evolvable.getDataVersion(),
evolvable.getImplVersion()));
}
for (Iterator> iter = m_tmd.getAttributes(); iter.hasNext(); )
{
TypeMetadata.AttributeMetadata attr = iter.next();
attr.getCodec().encode(out, attr.getIndex(), attr.get((T) o));
}
// write out any future properties
Binary binRemainder = null;
if (fEvolvable)
{
binRemainder = evolvable.getFutureData();
}
out.writeRemainder(binRemainder);
}
/**
* {@inheritDoc}
*/
public Object deserialize(PofReader in) throws IOException
{
TypeMetadata tmd = m_tmd;
T value = tmd.newInstance();
// set the version identifier
boolean fEvolvable = value instanceof Evolvable;
Evolvable evolvable = null;
if (fEvolvable)
{
evolvable = (Evolvable) value;
evolvable.setDataVersion(in.getVersionId());
}
for (Iterator> iter = tmd.getAttributes(); iter.hasNext(); )
{
TypeMetadata.AttributeMetadata attr = iter.next();
attr.set(value, attr.getCodec().decode(in, attr.getIndex()));
}
// read any future properties
Binary binRemainder = in.readRemainder();
if (fEvolvable)
{
evolvable.setFutureData(binRemainder);
}
return value;
}
// ----- helpers --------------------------------------------------------
/**
* Return the {@link TypeMetadata} instance that holds structural information
* regarding the class this serializer (de)serializes.
*
* @return a TypeMetadata instance for the class this serializer (de)serializes
*/
protected TypeMetadata getTypeMetadata()
{
return m_tmd;
}
/**
* Initialize this serializer with {@link TypeMetadata} pertaining to the
* specified class.
*
* @param clz class in question
* @param nTypeId POF type id that uniquely identifies this type
* @param fAutoIndex turns on the auto index feature
*
* @throws {@link IllegalArgumentException} if annotation is not present
* on {@code clz}
*/
private void initialize(int nTypeId, Class clz, boolean fAutoIndex)
{
Portable portable = clz.getAnnotation(Portable.class);
if (portable == null)
{
throw new IllegalArgumentException(String.format(
"Attempting to use %s for a class (%s) that has no %s annotation",
getClass().getSimpleName(),
clz.getName(),
Portable.class.getSimpleName()));
}
// via the builder create the type metadata
final ClassMetadataBuilder builder = new ClassMetadataBuilder()
.setTypeId(nTypeId);
builder.accept(new AnnotationVisitor(fAutoIndex), clz);
m_tmd = builder.build();
}
// ----- data members ---------------------------------------------------
/**
* TypeMetadata representing type information for this serializer
* instance
*/
private TypeMetadata m_tmd;
}