ProtoDeserializers.java

package net.morimekta.proto.jackson.adapter;

import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
import com.fasterxml.jackson.databind.module.SimpleDeserializers;
import com.fasterxml.jackson.databind.type.MapType;
import com.google.protobuf.Message;
import net.morimekta.proto.ProtoEnum;

import static net.morimekta.proto.ProtoEnum.getEnumDescriptorUnchecked;
import static net.morimekta.proto.ProtoMessage.getMessageDescriptor;

/**
 * Serializer handler for complex proto types.
 */
public class ProtoDeserializers
        extends SimpleDeserializers {
    @Override
    public JsonDeserializer<?> findMapDeserializer(MapType type,
                                                   DeserializationConfig config,
                                                   BeanDescription beanDesc,
                                                   KeyDeserializer keyDeserializer,
                                                   TypeDeserializer elementTypeDeserializer,
                                                   JsonDeserializer<?> elementDeserializer)
            throws JsonMappingException {
        if (ProtoEnum.isProtoEnumClass(type.getKeyType().getRawClass())) {
            return new ProtoMapDeserializer<>(
                    type.getRawClass(),
                    createEnumKeyDeserializer(type.getKeyType().getRawClass()),
                    type.getContentType());
        }
        return super.findMapDeserializer(type,
                                         config,
                                         beanDesc,
                                         keyDeserializer,
                                         elementTypeDeserializer,
                                         elementDeserializer);
    }

    @Override
    public JsonDeserializer<?> findEnumDeserializer(Class<?> type,
                                                    DeserializationConfig config,
                                                    BeanDescription beanDesc) throws JsonMappingException {
        if (ProtoEnum.isProtoEnumClass(type)) {
            try {
                return createEnumDeserializer(type);
            } catch (IllegalArgumentException e) {
                throw new JsonMappingException(null, e.getMessage(), e);
            }
        }
        return super.findEnumDeserializer(type, config, beanDesc);
    }

    @Override
    public JsonDeserializer<?> findBeanDeserializer(JavaType type,
                                                    DeserializationConfig config,
                                                    BeanDescription beanDesc) throws JsonMappingException {
        if (Message.class.isAssignableFrom(type.getRawClass())) {
            try {
                return this.createMessageDeserializer(type.getRawClass(), config);
            } catch (IllegalArgumentException e) {
                throw new JsonMappingException(null, e.getMessage(), e);
            }
        }
        return super.findBeanDeserializer(type, config, beanDesc);
    }

    private JsonDeserializer<?> createMessageDeserializer(Class<?> type, DeserializationConfig config) {
        return new ProtoMessageDeserializer<>(getMessageDescriptor(type), config);
    }

    @SuppressWarnings("rawtypes")
    private JsonDeserializer<?> createEnumDeserializer(Class<?> type) {
        return new ProtoEnumDeserializer(getEnumDescriptorUnchecked(type));
    }

    private KeyDeserializer createEnumKeyDeserializer(Class<?> type) {
        return new ProtoEnumKeyDeserializer(getEnumDescriptorUnchecked(type));
    }
}