
org.eclipse.serializer.Serializer Maven / Gradle / Ivy
package org.eclipse.serializer;
import static org.eclipse.serializer.util.X.mayNull;
import static org.eclipse.serializer.util.X.notNull;
import java.nio.ByteBuffer;
import java.util.function.Function;
/*-
* #%L
* Eclipse Serializer
* %%
* Copyright (C) 2023 MicroStream Software
* %%
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
* #L%
*/
import org.eclipse.serializer.collections.HashTable;
import org.eclipse.serializer.collections.types.XGettingCollection;
import org.eclipse.serializer.hashing.XHashing;
import org.eclipse.serializer.memory.XMemory;
import org.eclipse.serializer.persistence.binary.types.Binary;
import org.eclipse.serializer.persistence.binary.types.BinaryStorer;
import org.eclipse.serializer.persistence.binary.types.ChunksBuffer;
import org.eclipse.serializer.persistence.binary.types.ChunksBufferByteReversing;
import org.eclipse.serializer.persistence.binary.types.ChunksWrapper;
import org.eclipse.serializer.persistence.exceptions.PersistenceExceptionTransfer;
import org.eclipse.serializer.persistence.types.PersistenceIdSet;
import org.eclipse.serializer.persistence.types.PersistenceManager;
import org.eclipse.serializer.persistence.types.PersistenceObjectIdRequestor;
import org.eclipse.serializer.persistence.types.PersistenceObjectManager;
import org.eclipse.serializer.persistence.types.PersistenceSource;
import org.eclipse.serializer.persistence.types.PersistenceStoreHandler;
import org.eclipse.serializer.persistence.types.PersistenceStorer;
import org.eclipse.serializer.persistence.types.PersistenceTarget;
import org.eclipse.serializer.persistence.types.PersistenceTypeHandler;
import org.eclipse.serializer.persistence.types.PersistenceTypeHandlerManager;
import org.eclipse.serializer.persistence.types.Persister;
import org.eclipse.serializer.persistence.types.Storer;
import org.eclipse.serializer.reference.Lazy;
import org.eclipse.serializer.reference.ObjectSwizzling;
import org.eclipse.serializer.reference.Swizzling;
import org.eclipse.serializer.util.BufferSizeProviderIncremental;
import org.eclipse.serializer.util.X;
/**
* Convenient API layer to use the binary persistence functionality for a simple serializer.
*
* It is based on a {@link org.eclipse.serializer.SerializerFoundation}, which can be configured to various needs.
*
* Per default {@link Binary} and byte[]
are supported as medium types.
*
* @param the medium type
*/
public interface Serializer extends AutoCloseable
{
/**
* Serializes the given object graph into the medium type.
* @param object the graph's root
* @return the binary format
*/
public M serialize(Object object);
/**
* Recreates an object graph based on the given data.
* @param the object's type
* @param medium the medium to read from
* @return the deserialized object graph
*/
public T deserialize(M medium);
public static Serializer Bytes()
{
return Bytes(SerializerFoundation.New());
}
public static Serializer Bytes(final SerializerFoundation> foundation)
{
return New(
foundation ,
Static::toBytes ,
Static::toBinary
);
}
public static Serializer Binary()
{
return Binary(SerializerFoundation.New());
}
public static Serializer Binary(final SerializerFoundation> foundation)
{
return New(
foundation ,
Function.identity(),
Function.identity()
);
}
public static Serializer New(
final Function toMedium,
final Function toBinary
)
{
return New(
SerializerFoundation.New(),
toMedium ,
toBinary
);
}
public static Serializer New(
final SerializerFoundation> foundation,
final Function toMedium ,
final Function toBinary
)
{
return new Default<>(
notNull(foundation),
notNull(toMedium ),
notNull(toBinary )
);
}
public final static class Static
{
public static byte[] toBytes(final Binary binary)
{
return XMemory.toArray(binary.buffers());
}
public static Binary toBinary(final byte[] bytes)
{
final ByteBuffer buffer = XMemory.allocateDirectNative(bytes.length);
buffer.put(bytes);
buffer.flip();
return ChunksWrapper.New(buffer);
}
/**
* Dummy constructor to prevent instantiation of this static-only utility class.
*
* @throws UnsupportedOperationException when called
*/
private Static()
{
// static only
throw new UnsupportedOperationException();
}
}
public static interface Source extends PersistenceSource
{
@Override
default XGettingCollection extends Binary> readByObjectIds(final PersistenceIdSet[] oids)
throws PersistenceExceptionTransfer
{
return null;
}
}
public static interface Target extends PersistenceTarget
{
@Override
default boolean isWritable()
{
return true;
}
}
public static class Default implements Serializer
{
private final SerializerFoundation> foundation ;
private final Function toMedium ;
private final Function toBinary ;
private PersistenceManager persistenceManager;
private Storer storer ;
private Binary input ;
private Binary output ;
Default(
final SerializerFoundation> foundation,
final Function toMedium ,
final Function toBinary
)
{
super();
this.foundation = foundation;
this.toMedium = toMedium ;
this.toBinary = toBinary ;
this.lazyInit();
}
@Override
public synchronized M serialize(final Object object)
{
this.storer.store(object);
this.storer.commit();
return this.toMedium.apply(this.output);
}
@SuppressWarnings("unchecked")
@Override
public synchronized T deserialize(final M data)
{
this.input = this.toBinary.apply(data);
return (T)this.persistenceManager.get();
}
@Override
public synchronized void close()
{
if(this.persistenceManager != null)
{
this.persistenceManager.objectRegistry().truncateAll();
this.persistenceManager.close();
this.persistenceManager = null;
this.input = null;
this.output = null;
}
}
private void lazyInit()
{
if(this.persistenceManager == null)
{
final Source source = () -> X.Constant(this.input);
final Target target = data -> this.output = data ;
this.persistenceManager = this.foundation
.setPersistenceSource(source)
.setPersistenceTarget(target)
.createPersistenceManager()
;
this.storer = this.persistenceManager.createStorer(
new SerializerStorer.Creator(this.foundation.isByteOrderMismatch())
);
}
else
{
this.persistenceManager.objectRegistry().truncateAll();
}
}
static class SerializerStorer
implements BinaryStorer, PersistenceStoreHandler, PersistenceObjectIdRequestor
{
static class Creator implements PersistenceStorer.Creator
{
private final boolean switchByteOrder;
Creator(final boolean switchByteOrder)
{
super();
this.switchByteOrder = switchByteOrder;
}
@Override
public PersistenceStorer createLazyStorer(
final PersistenceTypeHandlerManager typeManager ,
final PersistenceObjectManager objectManager ,
final ObjectSwizzling objectRetriever ,
final PersistenceTarget target ,
final BufferSizeProviderIncremental bufferSizeProvider,
final Persister persister
)
{
return this.createEagerStorer(
typeManager ,
objectManager ,
objectRetriever ,
target ,
bufferSizeProvider,
persister
);
}
@Override
public PersistenceStorer createEagerStorer(
final PersistenceTypeHandlerManager typeManager ,
final PersistenceObjectManager objectManager ,
final ObjectSwizzling objectRetriever ,
final PersistenceTarget target ,
final BufferSizeProviderIncremental bufferSizeProvider,
final Persister persister
)
{
final SerializerStorer storer = new SerializerStorer(
objectManager ,
objectRetriever ,
typeManager ,
target ,
bufferSizeProvider ,
this.switchByteOrder,
persister
);
return storer;
}
}
protected static int defaultSlotSize()
{
return 1024;
}
private final boolean switchByteOrder;
private final PersistenceObjectManager objectManager ;
private final ObjectSwizzling objectRetriever;
private final PersistenceTypeHandlerManager typeManager ;
private final PersistenceTarget target ;
private final Persister persister ;
private final BufferSizeProviderIncremental bufferSizeProvider;
private ChunksBuffer[] chunks;
final Item head = new Item(null, 0L, null, null);
private Item tail;
private HashTable