ProvidenceObjectParser.java

package net.morimekta.providence.client.google;

import com.google.api.client.util.ObjectParser;
import net.morimekta.providence.PMessage;
import net.morimekta.providence.descriptor.PMessageDescriptor;
import net.morimekta.providence.serializer.JsonSerializer;
import net.morimekta.providence.serializer.Serializer;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.nio.charset.Charset;

/**
 * Object parser for providence messages.
 */
public class ProvidenceObjectParser implements ObjectParser {
    private final Serializer serializer;

    public ProvidenceObjectParser(Serializer serializer) {
        this.serializer = serializer;
    }

    @Nonnull
    private PMessageDescriptor getMessageDescriptor(Class<?> aClass) {
        try {
            Field kDescriptor = aClass.getDeclaredField("kDescriptor");
            return (PMessageDescriptor) kDescriptor.get(null);
        } catch (NoSuchFieldException | IllegalAccessException | ClassCastException e) {
            throw new IllegalArgumentException("Class " + aClass.getName() + " is not a providence message", e);
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T parseAndClose(InputStream inputStream, Charset charset, Class<T> aClass) throws IOException {
        try {
            PMessageDescriptor descriptor = getMessageDescriptor(aClass);
            return (T) serializer.deserialize(inputStream, descriptor);
        } finally {
            serializer.verifyEndOfContent(inputStream);
            inputStream.close();
        }
    }

    @Override
    public Object parseAndClose(InputStream inputStream, Charset charset, Type type) throws IOException {
        if (type instanceof Class && PMessage.class.isAssignableFrom((Class) type)) {
            return parseAndClose(inputStream, charset, (Class<?>) type);
        }
        throw new IllegalArgumentException("Class " + type.getTypeName() + " is not a providence message");
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T parseAndClose(Reader reader, Class<T> aClass) throws IOException {
        if (serializer instanceof JsonSerializer) {
            PMessageDescriptor descriptor = getMessageDescriptor(aClass);
            JsonSerializer json = (JsonSerializer) serializer;
            try {
                return (T) json.deserialize(reader, descriptor);
            } finally {
                json.verifyEndOfContent(reader);
                reader.close();
            }
        }

        throw new IllegalStateException("Serializer " + serializer.toString() + " does not support Reader deserialization");
    }

    @Override
    public Object parseAndClose(Reader reader, Type type) throws IOException {
        if (type instanceof Class && PMessage.class.isAssignableFrom((Class) type)) {
            return parseAndClose(reader, (Class<?>) type);
        }
        throw new IllegalArgumentException("Class " + type.getTypeName() + " is not a providence message");
    }
}