Skip to content

Instantly share code, notes, and snippets.

@egalpin
Last active June 9, 2022 17:01
Show Gist options
  • Save egalpin/c1ca7c58ee5e6fb1b67c5afd477fb339 to your computer and use it in GitHub Desktop.
Save egalpin/c1ca7c58ee5e6fb1b67c5afd477fb339 to your computer and use it in GitHub Desktop.
Jackson JSON serializer for Google Datastore Entity
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.google.cloud.Timestamp;
import com.google.cloud.datastore.Blob;
import com.google.cloud.datastore.Entity;
import com.google.cloud.datastore.Key;
import com.google.cloud.datastore.Value;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DatastoreEntitySerializer extends StdSerializer<Entity> {
private static final Logger LOG = LoggerFactory.getLogger(DatastoreEntitySerializer.class);
public DatastoreEntitySerializer() {
this(null);
}
public DatastoreEntitySerializer(Class<Entity> t) {
super(t);
}
private static void _serialize(Value<?> value, JsonGenerator gen) throws IOException {
switch (value.getType()) {
case STRING:
if ("null".equals(value.get())) {
gen.writeNull();
break;
}
gen.writeString((String) value.get());
break;
case KEY:
Key k = (Key) value.get();
gen.writeObject(k);
break;
case BLOB:
String encodedString =
Base64.getEncoder().encodeToString(((Blob) value.get()).toByteArray());
gen.writeString(encodedString);
break;
case BOOLEAN:
gen.writeBoolean((boolean) value.get());
break;
case DOUBLE:
gen.writeNumber((double) value.get());
break;
case NULL:
gen.writeNull();
break;
case LONG:
gen.writeNumber((long) value.get());
break;
case TIMESTAMP:
gen.writeNumber(toMillis((Timestamp) value.get()));
break;
case LIST:
gen.writeStartArray();
for (Value<?> v : (List<Value<?>>) value.get()) {
_serialize(v, gen);
}
gen.writeEndArray();
break;
case ENTITY:
serializeEntity((Entity) value.get(), gen);
break;
case LAT_LNG:
gen.writeString(value.get().toString());
break;
case RAW_VALUE:
default:
throw new UnsupportedEncodingException(
String.format("Cannot encode Datastore type %s", value.getType()));
}
}
public static void serializeEntity(Entity entity, JsonGenerator gen) throws IOException {
gen.writeStartObject();
Map<String, Value<?>> valueMap = entity.getProperties();
for (String field : entity.getNames()) {
Value<?> value = valueMap.get(field);
// value can only be one of ValueType enum
gen.writeFieldName(field);
try {
_serialize(value, gen);
} catch (UnsupportedEncodingException e) {
LOG.error(
String.format(
"Failed to serialize field %s from entity with Key %s", field, entity.getKey()));
throw e;
}
}
gen.writeEndObject();
}
private static long toMillis(Timestamp t) {
long secondsInMilliseconds = TimeUnit.SECONDS.toMillis(t.getSeconds());
long nanosInMilliseconds = TimeUnit.NANOSECONDS.toMillis(t.getNanos());
return secondsInMilliseconds + nanosInMilliseconds;
}
@Override
public void serialize(Entity entity, JsonGenerator gen, SerializerProvider provider)
throws IOException {
serializeEntity(entity, gen);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment