org.conqat.lib.commons.io.SerializationUtils 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
/*
* 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.io;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.conqat.lib.commons.assertion.CCSMAssert;
import org.conqat.lib.commons.filesystem.FileSystemUtils;
/**
* Utility methods for serialization.
*/
public class SerializationUtils {
/** Serializes an object to byte array */
public static byte[] serializeToByteArray(Serializable object) throws IOException {
ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();
ObjectOutputStream out = FilteredObjectStreams.filteredOutputStream(outBuffer);
try {
out.writeObject(object);
} catch (OutOfMemoryError e) {
if (e.getMessage() != null && //
(e.getMessage().matches("Required array length \\d+ \\+ \\d+ is too large")
|| e.getMessage().equals("Requested array size exceeds VM limit"))) {
OutOfMemoryError e1 = new OutOfMemoryError(String.format(
"Cannot serialize instance of type %s as it is too large to fit into a single byte[].",
object.getClass()));
// Cannot construct OOM with a cause, so add it as suppressed at least.
e1.addSuppressed(e);
throw e1;
}
throw e;
}
// no need to put this in finally, as we do not block file handles.
// Let the GC do the work
out.close();
return outBuffer.toByteArray();
}
/**
* Make use of StorageUtils#deserialize(byte[]) whenever possible. Only use this method as last
* resort.
*
* Deserializes an object from byte array using a custom/given class loader. Important:The
* caller has to ensure that the supplied class loader "knows" all classes to be deserialized.
* Returns null
if a null
value is passed.
*
*/
public static Serializable deserializeFromByteArray(byte[] bytes) throws IOException, ClassNotFoundException {
if (bytes == null) {
return null;
}
ObjectInputStream in = FilteredObjectStreams.filteredInputStream(new ByteArrayInputStream(bytes));
try {
return (Serializable) in.readObject();
} finally {
FileSystemUtils.close(in);
}
}
/**
* Returns a copy of the given object obtained by serialization and deserialization in memory.
*
*/
@SuppressWarnings("unchecked")
public static T cloneBySerialization(T t) {
try {
return (T) deserializeFromByteArray(serializeToByteArray(t));
} catch (IOException e) {
CCSMAssert.fail("This should be impossible as we are working in memory!");
return null;
} catch (ClassNotFoundException e) {
CCSMAssert.fail("This should be impossible as we just had the object available!");
return null;
}
}
/**
* Inserts an int value to the given position in the byte array. The storage will require 4 bytes in
* big endian byte order.
*/
public static void insertInt(int i, byte[] bytes, int position) {
bytes[position++] = (byte) (i >> 24 & 0xff);
bytes[position++] = (byte) (i >> 16 & 0xff);
bytes[position++] = (byte) (i >> 8 & 0xff);
bytes[position] = (byte) (i & 0xff);
}
/**
* Extracts an int value from the given array position (4 bytes in big endian). This is the counter
* part to {@link #insertInt(int, byte[], int)} .
*/
public static int extractInt(byte[] bytes, int position) {
int result = bytes[position++] & 0xff;
result <<= 8;
result |= bytes[position++] & 0xff;
result <<= 8;
result |= bytes[position++] & 0xff;
result <<= 8;
result |= bytes[position++] & 0xff;
return result;
}
/**
* Can be used in a {@code private void writeObject(ObjectOutputStream stream) throws IOException}
* implementation, to indicate that while the class implements {@link Serializable} it actually does
* not support serialization.
*
* @param ignoredStream
* Ignored input value. Can be provided to avoid unused parameter findings on their
* {@code ObjectOutputStream} until TS-38759 is resolved.
*/
public static void unsupportedWriteObject(@Nullable ObjectOutputStream ignoredStream) {
CCSMAssert.fail("Attempt to serialize an object, which should never be serialized");
}
/**
* Can be used in a
* {@code private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException}
* implementation, to indicate that while the class implements {@link Serializable} it actually does
* not support deserialization.
*
* @param ignoredStream
* Ignored input value. Can be provided to avoid unused parameter findings on their
* {@code ObjectInputStream} until TS-38759 is resolved.
*/
public static void unsupportedReadObject(@Nullable ObjectInputStream ignoredStream) {
CCSMAssert.fail("Attempt to deserialize an object, which should never be deserialized");
}
}