105 lines
4.5 KiB
Java
105 lines
4.5 KiB
Java
package tc.oc.api.document;
|
|
|
|
import java.lang.reflect.Type;
|
|
import java.util.Map;
|
|
import java.util.logging.Logger;
|
|
import javax.inject.Inject;
|
|
import javax.inject.Singleton;
|
|
|
|
import com.google.common.collect.ImmutableMap;
|
|
import com.google.common.reflect.TypeToken;
|
|
import com.google.gson.JsonDeserializationContext;
|
|
import com.google.gson.JsonDeserializer;
|
|
import com.google.gson.JsonElement;
|
|
import com.google.gson.JsonObject;
|
|
import com.google.gson.JsonParseException;
|
|
import com.google.gson.JsonSerializationContext;
|
|
import com.google.gson.JsonSerializer;
|
|
import com.google.gson.JsonSyntaxException;
|
|
import com.google.inject.CreationException;
|
|
import com.google.inject.ProvisionException;
|
|
import tc.oc.api.docs.virtual.Document;
|
|
import tc.oc.api.document.DocumentMeta;
|
|
import tc.oc.api.document.DocumentRegistry;
|
|
import tc.oc.api.document.Getter;
|
|
import tc.oc.api.exceptions.SerializationException;
|
|
import tc.oc.commons.core.logging.Loggers;
|
|
|
|
@Singleton
|
|
public class DocumentSerializer implements JsonSerializer<Document>, JsonDeserializer<Document> {
|
|
|
|
protected final Logger logger;
|
|
protected final DocumentRegistry documentRegistry;
|
|
|
|
@Inject DocumentSerializer(Loggers loggers, DocumentRegistry documentRegistry) {
|
|
this.logger = loggers.get(getClass());
|
|
this.documentRegistry = documentRegistry;
|
|
}
|
|
|
|
@Override
|
|
public JsonElement serialize(Document document, Type documentType, JsonSerializationContext context) {
|
|
final JsonObject documentJson = new JsonObject();
|
|
final DocumentMeta<?> documentMeta = documentRegistry.getMeta(document.getClass());
|
|
final TypeToken documentTypeToken = TypeToken.of(documentType);
|
|
|
|
for(Map.Entry<String, Getter> entry : documentMeta.getters().entrySet()) {
|
|
final String name = entry.getKey();
|
|
final Getter getter = entry.getValue();
|
|
final Type resolvedType = getter.resolvedType(documentTypeToken);
|
|
|
|
final Object value;
|
|
try {
|
|
value = getter.get(document);
|
|
} catch(Exception e) {
|
|
throw new SerializationException("Exception reading property " + resolvedType + " " + documentType + "." + name, e);
|
|
}
|
|
|
|
try {
|
|
documentJson.add(name, context.serialize(value, resolvedType));
|
|
} catch(Exception e) {
|
|
throw new SerializationException("Exception serializing property " + resolvedType + " " + documentType + "." + name + " = " + value, e);
|
|
}
|
|
}
|
|
|
|
return documentJson;
|
|
}
|
|
|
|
@Override
|
|
public Document deserialize(JsonElement rawJson, Type documentType, JsonDeserializationContext context) throws JsonParseException {
|
|
final TypeToken documentTypeToken = TypeToken.of(documentType);
|
|
final DocumentMeta<?> documentMeta = documentRegistry.getMeta(documentTypeToken.getRawType());
|
|
final Class<? extends Document> instantiableType = documentMeta.type();
|
|
|
|
if(!(rawJson instanceof JsonObject)) {
|
|
throw new JsonSyntaxException("Expected JSON object while deserializing " + instantiableType.getName() + ", not " + rawJson.getClass().getSimpleName());
|
|
}
|
|
final JsonObject documentJson = (JsonObject) rawJson;
|
|
final ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
|
|
|
|
for(Map.Entry<String, Getter> entry : documentMeta.getters().entrySet()) {
|
|
final String name = entry.getKey();
|
|
final Getter getter = entry.getValue();
|
|
final Type resolvedType = getter.resolvedType(documentTypeToken);
|
|
final JsonElement propertyJson = documentJson.get(name);
|
|
|
|
try {
|
|
if(propertyJson == null || propertyJson.isJsonNull()) {
|
|
if(!getter.isNullable()) {
|
|
throw new NullPointerException("Missing value for non-nullable property " + name);
|
|
}
|
|
} else {
|
|
builder.put(name, context.deserialize(propertyJson, resolvedType));
|
|
}
|
|
} catch(Exception e) {
|
|
throw new SerializationException("Exception deserializing property " + resolvedType + " " + documentType + "." + name + " = " + propertyJson, e);
|
|
}
|
|
}
|
|
|
|
try {
|
|
return documentRegistry.instantiate(documentMeta, builder.build());
|
|
} catch(ProvisionException | CreationException e) {
|
|
throw new SerializationException("Exception instantiating document " + instantiableType.getName(), e);
|
|
}
|
|
}
|
|
}
|