dev.restate.sdk.JsonSerdes Maven / Gradle / Ivy
// Copyright (c) 2023 - Restate Software, Inc., Restate GmbH
//
// This file is part of the Restate Java SDK,
// which is released under the MIT license.
//
// You can find a copy of the license in file LICENSE in the root
// directory of this repository or package, or at
// https://github.com/restatedev/sdk-java/blob/main/LICENSE
package dev.restate.sdk;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import dev.restate.sdk.common.Serde;
import dev.restate.sdk.common.function.ThrowingBiConsumer;
import dev.restate.sdk.common.function.ThrowingFunction;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.jspecify.annotations.NonNull;
/**
* Collection of common serializers/deserializers.
*
* To ser/de POJOs using JSON, you can use the module {@code sdk-serde-jackson}.
*/
public abstract class JsonSerdes {
private JsonSerdes() {}
/** {@link Serde} for {@link String}. This writes and reads {@link String} as JSON value. */
public static Serde<@NonNull String> STRING =
usingJackson(
JsonGenerator::writeString,
p -> {
if (p.nextToken() != JsonToken.VALUE_STRING) {
throw new IllegalStateException(
"Expecting token " + JsonToken.VALUE_STRING + ", got " + p.getCurrentToken());
}
return p.getText();
});
/** {@link Serde} for {@link Boolean}. This writes and reads {@link Boolean} as JSON value. */
public static Serde<@NonNull Boolean> BOOLEAN =
usingJackson(
JsonGenerator::writeBoolean,
p -> {
p.nextToken();
return p.getBooleanValue();
});
/** {@link Serde} for {@link Byte}. This writes and reads {@link Byte} as JSON value. */
public static Serde<@NonNull Byte> BYTE =
usingJackson(
JsonGenerator::writeNumber,
p -> {
p.nextToken();
return p.getByteValue();
});
/** {@link Serde} for {@link Short}. This writes and reads {@link Short} as JSON value. */
public static Serde<@NonNull Short> SHORT =
usingJackson(
JsonGenerator::writeNumber,
p -> {
p.nextToken();
return p.getShortValue();
});
/** {@link Serde} for {@link Integer}. This writes and reads {@link Integer} as JSON value. */
public static Serde<@NonNull Integer> INT =
usingJackson(
JsonGenerator::writeNumber,
p -> {
p.nextToken();
return p.getIntValue();
});
/** {@link Serde} for {@link Long}. This writes and reads {@link Long} as JSON value. */
public static Serde<@NonNull Long> LONG =
usingJackson(
JsonGenerator::writeNumber,
p -> {
p.nextToken();
return p.getLongValue();
});
/** {@link Serde} for {@link Float}. This writes and reads {@link Float} as JSON value. */
public static Serde<@NonNull Float> FLOAT =
usingJackson(
JsonGenerator::writeNumber,
p -> {
p.nextToken();
return p.getFloatValue();
});
/** {@link Serde} for {@link Double}. This writes and reads {@link Double} as JSON value. */
public static Serde<@NonNull Double> DOUBLE =
usingJackson(
JsonGenerator::writeNumber,
p -> {
p.nextToken();
return p.getDoubleValue();
});
// --- Helpers for jackson-core
private static final JsonFactory JSON_FACTORY = new JsonFactory();
private static Serde usingJackson(
ThrowingBiConsumer serializer,
ThrowingFunction deserializer) {
return new Serde<>() {
@Override
public byte[] serialize(T value) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (JsonGenerator gen = JSON_FACTORY.createGenerator(outputStream)) {
serializer.asBiConsumer().accept(gen, value);
} catch (IOException e) {
throw new RuntimeException("Cannot create JsonGenerator", e);
}
return outputStream.toByteArray();
}
@Override
public T deserialize(byte[] value) {
ByteArrayInputStream inputStream = new ByteArrayInputStream(value);
try (JsonParser parser = JSON_FACTORY.createParser(inputStream)) {
return deserializer.asFunction().apply(parser);
} catch (IOException e) {
throw new RuntimeException("Cannot create JsonGenerator", e);
}
}
@Override
public String contentType() {
return "application/json";
}
};
}
}