Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.protostuff.runtime.DefaultIdStrategy Maven / Gradle / Ivy
package io.protostuff.runtime;
import static io.protostuff.runtime.RuntimeFieldFactory.ID_BOOL;
import static io.protostuff.runtime.RuntimeFieldFactory.ID_BYTE;
import static io.protostuff.runtime.RuntimeFieldFactory.ID_CHAR;
import static io.protostuff.runtime.RuntimeFieldFactory.ID_DOUBLE;
import static io.protostuff.runtime.RuntimeFieldFactory.ID_FLOAT;
import static io.protostuff.runtime.RuntimeFieldFactory.ID_INT32;
import static io.protostuff.runtime.RuntimeFieldFactory.ID_INT64;
import static io.protostuff.runtime.RuntimeFieldFactory.ID_SHORT;
import io.protostuff.CollectionSchema;
import io.protostuff.Input;
import io.protostuff.MapSchema;
import io.protostuff.Message;
import io.protostuff.Output;
import io.protostuff.Pipe;
import io.protostuff.ProtostuffException;
import io.protostuff.Schema;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* The FQCN(fully qualified class name) will serve as the id (string). Does not need any registration in the user-code
* (works out-of-the-box). The size of serialized representation may be not very efficient.
*
* @author Leo Romanoff
* @author David Yu
*/
public final class DefaultIdStrategy extends IdStrategy
{
final ConcurrentHashMap> pojoMapping = new ConcurrentHashMap>();
final ConcurrentHashMap> enumMapping = new ConcurrentHashMap>();
final ConcurrentHashMap collectionMapping = new ConcurrentHashMap();
final ConcurrentHashMap mapMapping = new ConcurrentHashMap();
final ConcurrentHashMap> delegateMapping = new ConcurrentHashMap>();
public DefaultIdStrategy()
{
super(DEFAULT_FLAGS, null, 0);
}
public DefaultIdStrategy(IdStrategy primaryGroup, int groupId)
{
super(DEFAULT_FLAGS, primaryGroup, groupId);
}
public DefaultIdStrategy(int flags, IdStrategy primaryGroup, int groupId)
{
super(flags, primaryGroup, groupId);
}
/**
* Registers a pojo. Returns true if registration is successful or if the same exact schema was previously
* registered. Used by {@link RuntimeSchema#register(Class, Schema)}.
*/
public boolean registerPojo(Class typeClass, Schema schema)
{
assert typeClass != null && schema != null;
final HasSchema> last = pojoMapping.putIfAbsent(typeClass.getName(),
new Registered(schema, this));
return last == null
|| (last instanceof Registered> && ((Registered>) last).schema == schema);
}
/**
* Registers a pojo. Returns true if registration is successful or if the same exact schema was previously
* registered.
*/
public boolean registerPojo(Class typeClass)
{
assert typeClass != null;
final HasSchema> last = pojoMapping.putIfAbsent(typeClass.getName(),
new LazyRegister(typeClass, this));
return last == null || (last instanceof LazyRegister);
}
/**
* Registers an enum. Returns true if registration is successful.
*/
public > boolean registerEnum(Class enumClass)
{
return null == enumMapping.putIfAbsent(enumClass.getName(),
EnumIO.newEnumIO(enumClass, this));
}
/**
* Registers a delegate. Returns true if registration is successful.
*/
public boolean registerDelegate(Delegate delegate)
{
return null == delegateMapping.putIfAbsent(delegate.typeClass()
.getName(), new HasDelegate(delegate, this));
}
/**
* Registers a collection. Returns true if registration is successful.
*/
public boolean registerCollection(CollectionSchema.MessageFactory factory)
{
return null == collectionMapping.putIfAbsent(factory.typeClass()
.getName(), factory);
}
/**
* Registers a map. Returns true if registration is successful.
*/
public boolean registerMap(MapSchema.MessageFactory factory)
{
return null == mapMapping.putIfAbsent(factory.typeClass().getName(),
factory);
}
/**
* Used by {@link RuntimeSchema#map(Class, Class)}.
*/
public boolean map(Class super T> baseClass, Class typeClass)
{
assert baseClass != null && typeClass != null;
if (typeClass.isInterface()
|| Modifier.isAbstract(typeClass.getModifiers()))
{
throw new IllegalArgumentException(typeClass
+ " cannot be an interface/abstract class.");
}
final HasSchema> last = pojoMapping.putIfAbsent(baseClass.getName(),
new Mapped(baseClass, typeClass, this));
return last == null
|| (last instanceof Mapped> && ((Mapped>) last).typeClass == typeClass);
}
@Override
public boolean isDelegateRegistered(Class> typeClass)
{
return delegateMapping.containsKey(typeClass.getName());
}
@Override
@SuppressWarnings("unchecked")
public HasDelegate getDelegateWrapper(Class super T> typeClass)
{
return (HasDelegate) delegateMapping.get(typeClass.getName());
}
@Override
@SuppressWarnings("unchecked")
public Delegate getDelegate(Class super T> typeClass)
{
final HasDelegate last = (HasDelegate) delegateMapping
.get(typeClass.getName());
return last == null ? null : last.delegate;
}
@Override
public boolean isRegistered(Class> typeClass)
{
final HasSchema> last = pojoMapping.get(typeClass.getName());
return last != null && !(last instanceof Lazy>);
}
@SuppressWarnings("unchecked")
private HasSchema getSchemaWrapper(String className, boolean load)
{
HasSchema hs = (HasSchema) pojoMapping.get(className);
if (hs == null)
{
if (!load)
return null;
final Class typeClass = RuntimeEnv.loadClass(className);
hs = new Lazy(typeClass, this);
final HasSchema last = (HasSchema) pojoMapping.putIfAbsent(
typeClass.getName(), hs);
if (last != null)
hs = last;
}
return hs;
}
@Override
@SuppressWarnings("unchecked")
public HasSchema getSchemaWrapper(Class typeClass, boolean create)
{
HasSchema hs = (HasSchema) pojoMapping.get(typeClass.getName());
if (hs == null && create)
{
hs = new Lazy(typeClass, this);
final HasSchema last = (HasSchema) pojoMapping.putIfAbsent(
typeClass.getName(), hs);
if (last != null)
hs = last;
}
return hs;
}
private EnumIO extends Enum>> getEnumIO(String className, boolean load)
{
EnumIO> eio = enumMapping.get(className);
if (eio == null)
{
if (!load)
return null;
final Class> enumClass = RuntimeEnv.loadClass(className);
eio = EnumIO.newEnumIO(enumClass, this);
final EnumIO> existing = enumMapping.putIfAbsent(
enumClass.getName(), eio);
if (existing != null)
eio = existing;
}
return eio;
}
@Override
protected EnumIO extends Enum>> getEnumIO(Class> enumClass)
{
EnumIO> eio = enumMapping.get(enumClass.getName());
if (eio == null)
{
eio = EnumIO.newEnumIO(enumClass, this);
final EnumIO> existing = enumMapping.putIfAbsent(
enumClass.getName(), eio);
if (existing != null)
eio = existing;
}
return eio;
}
@Override
protected CollectionSchema.MessageFactory getCollectionFactory(
Class> clazz)
{
final String className = clazz.getName();
CollectionSchema.MessageFactory factory = collectionMapping
.get(className);
if (factory == null)
{
if (className.startsWith("java.util"))
{
factory = CollectionSchema.MessageFactories.valueOf(clazz
.getSimpleName());
}
else
{
factory = new RuntimeCollectionFactory(clazz);
CollectionSchema.MessageFactory f = collectionMapping
.putIfAbsent(className, factory);
if (f != null)
factory = f;
}
}
return factory;
}
@Override
protected MapSchema.MessageFactory getMapFactory(Class> clazz)
{
final String className = clazz.getName();
MapSchema.MessageFactory factory = mapMapping.get(className);
if (factory == null)
{
if (className.startsWith("java.util"))
{
factory = MapSchema.MessageFactories.valueOf(clazz
.getSimpleName());
}
else
{
factory = new RuntimeMapFactory(clazz);
MapSchema.MessageFactory f = mapMapping.putIfAbsent(className,
factory);
if (f != null)
factory = f;
}
}
return factory;
}
@Override
protected void writeCollectionIdTo(Output output, int fieldNumber,
Class> clazz) throws IOException
{
final CollectionSchema.MessageFactory factory = collectionMapping
.get(clazz);
if (factory == null && clazz.getName().startsWith("java.util"))
{
// jdk collection
// better not to register the jdk collection if using this strategy
// as it saves space by not writing the full package
output.writeString(fieldNumber, clazz.getSimpleName(), false);
}
else
{
output.writeString(fieldNumber, clazz.getName(), false);
}
}
@Override
protected void transferCollectionId(Input input, Output output,
int fieldNumber) throws IOException
{
input.transferByteRangeTo(output, true, fieldNumber, false);
}
@Override
protected CollectionSchema.MessageFactory resolveCollectionFrom(Input input)
throws IOException
{
final String className = input.readString();
CollectionSchema.MessageFactory factory = collectionMapping
.get(className);
if (factory == null)
{
if (className.indexOf('.') == -1)
{
factory = CollectionSchema.MessageFactories.valueOf(className);
}
else
{
factory = new RuntimeCollectionFactory(
RuntimeEnv.loadClass(className));
CollectionSchema.MessageFactory f = collectionMapping
.putIfAbsent(className, factory);
if (f != null)
factory = f;
}
}
return factory;
}
@Override
protected void writeMapIdTo(Output output, int fieldNumber, Class> clazz)
throws IOException
{
final MapSchema.MessageFactory factory = mapMapping.get(clazz);
if (factory == null && clazz.getName().startsWith("java.util"))
{
// jdk map
// better not to register the jdk map if using this strategy
// as it saves space by not writing the full package
output.writeString(fieldNumber, clazz.getSimpleName(), false);
}
else
{
output.writeString(fieldNumber, clazz.getName(), false);
}
}
@Override
protected void transferMapId(Input input, Output output, int fieldNumber)
throws IOException
{
input.transferByteRangeTo(output, true, fieldNumber, false);
}
@Override
protected MapSchema.MessageFactory resolveMapFrom(Input input)
throws IOException
{
final String className = input.readString();
MapSchema.MessageFactory factory = mapMapping.get(className);
if (factory == null)
{
if (className.indexOf('.') == -1)
{
factory = MapSchema.MessageFactories.valueOf(className);
}
else
{
factory = new RuntimeMapFactory(RuntimeEnv.loadClass(className));
MapSchema.MessageFactory f = mapMapping.putIfAbsent(className,
factory);
if (f != null)
factory = f;
}
}
return factory;
}
@Override
protected void writeEnumIdTo(Output output, int fieldNumber, Class> clazz)
throws IOException
{
output.writeString(fieldNumber, clazz.getName(), false);
}
@Override
protected void transferEnumId(Input input, Output output, int fieldNumber)
throws IOException
{
input.transferByteRangeTo(output, true, fieldNumber, false);
}
@Override
protected EnumIO> resolveEnumFrom(Input input) throws IOException
{
return getEnumIO(input.readString(), true);
}
@Override
@SuppressWarnings("unchecked")
protected HasDelegate tryWriteDelegateIdTo(Output output,
int fieldNumber, Class clazz) throws IOException
{
final HasDelegate hd = (HasDelegate) delegateMapping.get(clazz
.getName());
if (hd == null)
return null;
output.writeString(fieldNumber, clazz.getName(), false);
return hd;
}
@Override
@SuppressWarnings("unchecked")
protected HasDelegate transferDelegateId(Input input, Output output,
int fieldNumber) throws IOException
{
final String className = input.readString();
final HasDelegate hd = (HasDelegate) delegateMapping
.get(className);
if (hd == null)
throw new UnknownTypeException("delegate: " + className
+ " (Outdated registry)");
output.writeString(fieldNumber, className, false);
return hd;
}
@Override
@SuppressWarnings("unchecked")
protected HasDelegate resolveDelegateFrom(Input input)
throws IOException
{
final String className = input.readString();
final HasDelegate hd = (HasDelegate) delegateMapping
.get(className);
if (hd == null)
throw new UnknownTypeException("delegate: " + className
+ " (Outdated registry)");
return hd;
}
@Override
protected HasSchema tryWritePojoIdTo(Output output, int fieldNumber,
Class clazz, boolean registered) throws IOException
{
HasSchema hs = getSchemaWrapper(clazz, false);
if (hs == null || (registered && hs instanceof Lazy>))
return null;
output.writeString(fieldNumber, clazz.getName(), false);
return hs;
}
@Override
protected HasSchema writePojoIdTo(Output output, int fieldNumber,
Class clazz) throws IOException
{
output.writeString(fieldNumber, clazz.getName(), false);
// it is important to return the schema initialized (if it hasn't been).
return getSchemaWrapper(clazz, true);
}
@Override
protected HasSchema transferPojoId(Input input, Output output,
int fieldNumber) throws IOException
{
final String className = input.readString();
final HasSchema wrapper = getSchemaWrapper(className,
0 != (AUTO_LOAD_POLYMORPHIC_CLASSES & flags));
if (wrapper == null)
{
throw new ProtostuffException("polymorphic pojo not registered: "
+ className);
}
output.writeString(fieldNumber, className, false);
return wrapper;
}
@Override
protected HasSchema resolvePojoFrom(Input input, int fieldNumber)
throws IOException
{
final String className = input.readString();
final HasSchema wrapper = getSchemaWrapper(className,
0 != (AUTO_LOAD_POLYMORPHIC_CLASSES & flags));
if (wrapper == null)
throw new ProtostuffException("polymorphic pojo not registered: "
+ className);
return wrapper;
}
@Override
protected Schema writeMessageIdTo(Output output, int fieldNumber,
Message message) throws IOException
{
output.writeString(fieldNumber, message.getClass().getName(), false);
return message.cachedSchema();
}
@Override
protected void writeArrayIdTo(Output output, Class> componentType)
throws IOException
{
output.writeString(RuntimeFieldFactory.ID_ARRAY,
componentType.getName(), false);
}
@Override
protected void transferArrayId(Input input, Output output, int fieldNumber,
boolean mapped) throws IOException
{
input.transferByteRangeTo(output, true, fieldNumber, false);
}
@Override
protected Class> resolveArrayComponentTypeFrom(Input input, boolean mapped)
throws IOException
{
return resolveClass(input.readString());
}
static Class> resolveClass(String className)
{
final RuntimeFieldFactory inline = RuntimeFieldFactory
.getInline(className);
if (inline == null)
return RuntimeEnv.loadClass(className);
if (className.indexOf('.') != -1)
return inline.typeClass();
switch (inline.id)
{
case ID_BOOL:
return boolean.class;
case ID_BYTE:
return byte.class;
case ID_CHAR:
return char.class;
case ID_SHORT:
return short.class;
case ID_INT32:
return int.class;
case ID_INT64:
return long.class;
case ID_FLOAT:
return float.class;
case ID_DOUBLE:
return double.class;
default:
throw new RuntimeException("Should never happen.");
}
}
@Override
protected void writeClassIdTo(Output output, Class> componentType,
boolean array) throws IOException
{
final int id = array ? RuntimeFieldFactory.ID_CLASS_ARRAY
: RuntimeFieldFactory.ID_CLASS;
output.writeString(id, componentType.getName(), false);
}
@Override
protected void transferClassId(Input input, Output output, int fieldNumber,
boolean mapped, boolean array) throws IOException
{
input.transferByteRangeTo(output, true, fieldNumber, false);
}
@Override
protected Class> resolveClassFrom(Input input, boolean mapped,
boolean array) throws IOException
{
return resolveClass(input.readString());
}
static final class RuntimeCollectionFactory implements
CollectionSchema.MessageFactory
{
final Class> collectionClass;
final RuntimeEnv.Instantiator> instantiator;
public RuntimeCollectionFactory(Class> collectionClass)
{
this.collectionClass = collectionClass;
instantiator = RuntimeEnv.newInstantiator(collectionClass);
}
@Override
@SuppressWarnings("unchecked")
public Collection newMessage()
{
return (Collection) instantiator.newInstance();
}
@Override
public Class> typeClass()
{
return collectionClass;
}
}
static final class RuntimeMapFactory implements MapSchema.MessageFactory
{
final Class> mapClass;
final RuntimeEnv.Instantiator> instantiator;
public RuntimeMapFactory(Class> mapClass)
{
this.mapClass = mapClass;
instantiator = RuntimeEnv.newInstantiator(mapClass);
}
@Override
@SuppressWarnings("unchecked")
public Map newMessage()
{
return (Map) instantiator.newInstance();
}
@Override
public Class> typeClass()
{
return mapClass;
}
}
static final class Lazy extends HasSchema
{
final Class typeClass;
private volatile Schema schema;
private volatile Pipe.Schema pipeSchema;
Lazy(Class typeClass, IdStrategy strategy)
{
super(strategy);
this.typeClass = typeClass;
}
@Override
@SuppressWarnings("unchecked")
public Schema getSchema()
{
Schema schema = this.schema;
if (schema == null)
{
synchronized (this)
{
if ((schema = this.schema) == null)
{
if (Message.class.isAssignableFrom(typeClass))
{
// use the message's schema.
Message m = (Message) createMessageInstance(typeClass);
this.schema = schema = m.cachedSchema();
}
else
{
// create new
this.schema = schema = strategy
.newSchema(typeClass);
}
}
}
}
return schema;
}
@Override
public Pipe.Schema getPipeSchema()
{
Pipe.Schema pipeSchema = this.pipeSchema;
if (pipeSchema == null)
{
synchronized (this)
{
if ((pipeSchema = this.pipeSchema) == null)
{
this.pipeSchema = pipeSchema = RuntimeSchema
.resolvePipeSchema(getSchema(), typeClass, true);
}
}
}
return pipeSchema;
}
}
static final class Mapped extends HasSchema
{
final Class super T> baseClass;
final Class typeClass;
private volatile HasSchema wrapper;
Mapped(Class super T> baseClass, Class typeClass,
IdStrategy strategy)
{
super(strategy);
this.baseClass = baseClass;
this.typeClass = typeClass;
}
@Override
public Schema getSchema()
{
HasSchema wrapper = this.wrapper;
if (wrapper == null)
{
synchronized (this)
{
if ((wrapper = this.wrapper) == null)
{
this.wrapper = wrapper = strategy.getSchemaWrapper(
typeClass, true);
}
}
}
return wrapper.getSchema();
}
@Override
public Pipe.Schema getPipeSchema()
{
HasSchema wrapper = this.wrapper;
if (wrapper == null)
{
synchronized (this)
{
if ((wrapper = this.wrapper) == null)
{
this.wrapper = wrapper = strategy.getSchemaWrapper(
typeClass, true);
}
}
}
return wrapper.getPipeSchema();
}
}
static final class LazyRegister extends HasSchema
{
final Class typeClass;
private volatile Schema schema;
private volatile Pipe.Schema pipeSchema;
LazyRegister(Class typeClass, IdStrategy strategy)
{
super(strategy);
this.typeClass = typeClass;
}
@Override
public Schema getSchema()
{
Schema schema = this.schema;
if (schema == null)
{
synchronized (this)
{
if ((schema = this.schema) == null)
{
// create new
this.schema = schema = strategy.newSchema(typeClass);
}
}
}
return schema;
}
@Override
public Pipe.Schema getPipeSchema()
{
Pipe.Schema pipeSchema = this.pipeSchema;
if (pipeSchema == null)
{
synchronized (this)
{
if ((pipeSchema = this.pipeSchema) == null)
{
this.pipeSchema = pipeSchema = RuntimeSchema
.resolvePipeSchema(getSchema(), typeClass, true);
}
}
}
return pipeSchema;
}
}
static final class Registered extends HasSchema
{
final Schema schema;
private volatile Pipe.Schema pipeSchema;
Registered(Schema schema, IdStrategy strategy)
{
super(strategy);
this.schema = schema;
}
@Override
public Schema getSchema()
{
return schema;
}
@Override
public Pipe.Schema getPipeSchema()
{
Pipe.Schema pipeSchema = this.pipeSchema;
if (pipeSchema == null)
{
synchronized (this)
{
if ((pipeSchema = this.pipeSchema) == null)
{
this.pipeSchema = pipeSchema = RuntimeSchema
.resolvePipeSchema(schema, schema.typeClass(),
true);
}
}
}
return pipeSchema;
}
}
}