org.conqat.lib.commons.serialization.SerializedEntitySerializer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of teamscale-lib-commons Show documentation
Show all versions of teamscale-lib-commons Show documentation
Provides common utility functions
The newest version!
/*
* Copyright (c) CQSE GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.conqat.lib.commons.serialization;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectStreamConstants;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import org.conqat.lib.commons.assertion.CCSMAssert;
import org.conqat.lib.commons.serialization.objects.LongStringUtils;
import org.conqat.lib.commons.serialization.objects.SerializedObjectBase;
import org.conqat.lib.commons.serialization.objects.SerializedStringObject;
/**
* Serializes serialized entities (objects + classes) back to a stream.
*/
public class SerializedEntitySerializer {
/** Maximal allowed size for short block data. */
private static final int MAX_SHORT_BLOCK_DATA_SIZE = 255;
/** The stream to write into. */
private final DataOutputStream dos;
/** Counter used to determine the next entity handle. */
private int nextHandle = SerializedEntityPool.START_HANDLE;
/** Entities already written together with their handles. */
private final Map entityPool = new IdentityHashMap<>();
/**
* Strings already written together with their handles. This is kept separate from the
* {@link #entityPool} to allow exploitation of (accidental) equality in strings.
*/
private final Map stringPool = new HashMap<>();
/** Constructor. */
private SerializedEntitySerializer(DataOutputStream dos) {
this.dos = dos;
}
/** Performs the actual serialization. */
private void serialize(List entities) throws IOException {
dos.writeShort(ObjectStreamConstants.STREAM_MAGIC);
dos.writeShort(ObjectStreamConstants.STREAM_VERSION);
for (SerializedEntityBase entity : entities) {
if (entity == null) {
dos.writeByte(ObjectStreamConstants.TC_NULL);
} else {
entity.serialize(dos, this);
}
}
}
/** Serializes a pool to a data output stream. */
public static void serializeToStream(List entities, DataOutputStream dos)
throws IOException {
new SerializedEntitySerializer(dos).serialize(entities);
}
/** Serializes a pool to an output stream. */
public static void serializeToStream(List entities, OutputStream out)
throws IOException {
DataOutputStream dos = new DataOutputStream(out);
serializeToStream(entities, dos);
dos.flush();
}
/**
* Serializes a pool to a raw array.
*/
public static byte[] serializeToBytes(List entities) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializeToStream(entities, baos);
baos.close();
return baos.toByteArray();
}
/** Serializes a string as an object. */
public void serializeStringObject(String value) throws IOException {
serializeStringObject(value, true);
}
/** Serializes a string as an object. */
public void serializeStringObject(String value, boolean useStringPool) throws IOException {
if (useStringPool) {
Integer existingHandle = stringPool.get(value);
if (existingHandle != null) {
dos.writeByte(ObjectStreamConstants.TC_REFERENCE);
dos.writeInt(existingHandle);
return;
}
}
stringPool.put(value, obtainHandle());
if (value.length() <= LongStringUtils.MAX_SHORT_STRING_LENGTH) {
dos.writeByte(ObjectStreamConstants.TC_STRING);
dos.writeUTF(value);
} else {
dos.writeByte(ObjectStreamConstants.TC_LONGSTRING);
LongStringUtils.writeUTF(value, dos);
}
}
/** Writes a raw block of data. */
public void writeBlockData(byte[] data) throws IOException {
if (data.length <= MAX_SHORT_BLOCK_DATA_SIZE) {
dos.write(ObjectStreamConstants.TC_BLOCKDATA);
dos.writeByte(data.length);
} else {
dos.write(ObjectStreamConstants.TC_BLOCKDATALONG);
dos.writeInt(data.length);
}
dos.write(data);
}
/**
* Serializes an annotation list as found in objectAnnotation
and
* classAnnotation
. Note that this has nothing to do with Java annotations (the
* language feature), but rather is a list consisting of raw data (byte arrays) and handles (int).
*/
public void serializeAnnotationList(List