This pair of interfaces is configured using ChronicleMapBuilder.keyMarshallers()
or
valueMarshallers()
for the key, or value type, of the map, respectively. Overloaded methods; those
for [BytesWriter
and BytesReader
](#byteswriter-and-bytesreader) interfaces have the same names).
The main two methods to implement in SizedWriter
interface are:
-
long size(@NotNull T toWrite);
returns the number of bytes, which is written by the subsequentwrite()
method given the sametoWrite
instance of the serialized type. -
void write(Bytes out, long size, @NotNull T toWrite);
writes the giventoWrite
instance to the givenout
bytes sink. Additionally,size
is provided, which is the value computed for the sametoWrite
instance by callingsize()
method. WhenSizedWriter
is used internally, thesize()
method is always called beforewrite()
; caching logic inSizedWriter
implementation may rely on this. This method should advance thewritePosition()
of the given outBytes
exactly by the givensize
number of bytes.
SizedReader’s `T read(Bytes in, long size, @Nullable T using);
method is similar to the
corresponding read()
method in BytesReader
interface, except that the size of the serialized object is provided.
This pair of interfaces is suitable, if:
-
The serialized form of the type effectively includes the size of the rest of the serialized form in the beginning.
-
The type is not a plain sequence of bytes; for example,
byte[]
orByteBuffer
. Forbyte[]
orByteBuffer
, theDataAccess
andSizedReader
pair of interfaces is a much better choice.
Examples of such types include lists, and arrays of constant-sized elements.
Compared to BytesWriter
and BytesReader
, this pair of interfaces allows the sharing of information
about the serialized form, between serialization logic, and the Chronicle Map; this saves a few bytes by storing the serialization size only once, rather than twice. This pair of interfaces is not much more difficult to implement, but the gains are also not large.
Example: Serializing lists of simple Point
structures:
public final class Point {
public static Point of(double x, double y) {
Point p = new Point();
p.x = x;
p.y = y;
return p;
}
double x, y;
}
Serializer implementation:
public final class PointListSizedMarshaller
implements SizedReader<List<Point>>, SizedWriter<List<Point>>,
ReadResolvable<PointListSizedMarshaller> {
static final PointListSizedMarshaller INSTANCE = new PointListSizedMarshaller();
private PointListSizedMarshaller() {}
/** A point takes 16 bytes in serialized form: 8 bytes for both x and y value */
private static final long ELEMENT_SIZE = 16;
@Override
public long size(@NotNull List<Point> toWrite) {
return toWrite.size() * ELEMENT_SIZE;
}
@Override
public void write(Bytes out, long size, @NotNull List<Point> toWrite) {
toWrite.forEach(point -> {
out.writeDouble(point.x);
out.writeDouble(point.y);
});
}
@NotNull
@Override
public List<Point> read(@NotNull Bytes in, long size, List<Point> using) {
if (size % ELEMENT_SIZE != 0) {
throw new IORuntimeException("Bytes size should be a multiple of " + ELEMENT_SIZE +
", " + size + " read");
}
long listSizeAsLong = size / ELEMENT_SIZE;
if (listSizeAsLong > Integer.MAX_VALUE) {
throw new IORuntimeException("List size couldn't be more than " + Integer.MAX_VALUE +
", " + listSizeAsLong + " read");
}
int listSize = (int) listSizeAsLong;
if (using == null) {
using = new ArrayList<>(listSize);
for (int i = 0; i < listSize; i++) {
using.add(null);
}
} else if (using.size() < listSize) {
while (using.size() < listSize) {
using.add(null);
}
} else if (using.size() > listSize) {
using.subList(listSize, using.size()).clear();
}
for (int i = 0; i < listSize; i++) {
Point point = using.get(i);
if (point == null)
using.set(i, point = new Point());
point.x = in.readDouble();
point.y = in.readDouble();
}
return using;
}
@Override
public void writeMarshallable(@NotNull WireOut wireOut) {
// no fields to write
}
@Override
public void readMarshallable(@NotNull WireIn wireIn) {
// no fields to read
}
@Override
public PointListSizedMarshaller readResolve() {
return INSTANCE;
}
}
Usage example:
try (ChronicleMa p<String, List<Point>> objects = ChronicleMap
.of(String.class, (Class<List<Point>>) (Class) List.class)
.averageKey("range")
.valueMarshaller(PointListSizedMarshaller.INSTANCE)
.averageValue(asList(of(0, 0), of(1, 1)))
.entries(10)
.create()) {
objects.put("range", asList(of(0, 0), of(1, 1)));
objects.put("square", asList(of(0, 0), of(0, 100), of(100, 100), of(100, 0)));
Assert.assertEquals(2, objects.get("range").size());
Assert.assertEquals(4, objects.get("square").size());
}