com.github.cherimojava.data.spring.EntityConverter.java Source code

Java tutorial

Introduction

Here is the source code for com.github.cherimojava.data.spring.EntityConverter.java

Source

/**
 * Copyright (C) 2013 cherimojava (http://github.com/cherimojava/cherimodata/spring) Licensed under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy
 * of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in
 * writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
 * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.cherimojava.data.spring;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;

import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.GenericHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;

import com.github.cherimojava.data.mongo.entity.Entity;
import com.github.cherimojava.data.mongo.entity.EntityFactory;
import com.google.common.base.Charsets;

/**
 * Converts a JSON HTTPMessage to and from Entity. To enable this converter you need to add it to your
 * {@link org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter}. This can happen through
 * overriding the appropriate {@link org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport}
 * methods like
 * {@link org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#configureMessageConverters} or
 * {@link org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#addDefaultHttpMessageConverters}
 *
 * @author philnate
 * @since 1.0.0
 */
public class EntityConverter extends AbstractHttpMessageConverter<Object>
        implements GenericHttpMessageConverter<Object> {

    private final EntityFactory factory;

    /**
     * creates a new EntityConverter which utilizes the given @{link
     * com.github.cherimojava.data.mongo.entity.EntityFactory}
     *
     * @param factory to be used to convert from/to HTTPMessage/Entity
     */
    public EntityConverter(EntityFactory factory) {
        super(MediaType.APPLICATION_JSON);
        this.factory = factory;
    }

    /**
     * Checks if the given class can be handled by this Converter or not. Returns true for all
     * {@link com.github.cherimojava.data.mongo.entity.Entity} based classes, false otherwise
     *
     * @param clazz to check if it's supported
     * @return true if the given class can be assigned to Entity, false otherwise
     */
    @Override
    protected boolean supports(Class<?> clazz) {
        return Entity.class.isAssignableFrom(clazz);
    }

    @Override
    protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException {
        return fromJson((Class<? extends Entity>) clazz, inputMessage);
    }

    @Override
    public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException {
        // as this method is only called after we decided that we can decode the requested type, we only need to check
        // what we have (plain entity/list of entities)
        if (type instanceof Class) {
            // simple class
            return factory.readEntity((Class<? extends Entity>) type, IOUtils.toString(inputMessage.getBody()));
        } else {
            // collection
            return factory.readList(
                    (Class<? extends Entity>) ((ParameterizedType) type).getActualTypeArguments()[0],
                    IOUtils.toString(inputMessage.getBody()));
        }
    }

    private Entity fromJson(Class<? extends Entity> clazz, HttpInputMessage inputMessage) throws IOException {
        return factory.readEntity(clazz, IOUtils.toString(inputMessage.getBody(), Charsets.UTF_8.name()));
    }

    @Override
    protected void writeInternal(Object o, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException {
        try (OutputStreamWriter osw = new OutputStreamWriter(outputMessage.getBody())) {
            osw.write(o.toString());
        }
    }

    @Override
    public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) {
        if (MediaType.APPLICATION_JSON.equals(mediaType)) {
            if (type instanceof Class) {
                // check if this is a simple entity class
                return Entity.class.isAssignableFrom((Class) type);
            }
            if (type instanceof ParameterizedType) {
                // is this a parameterized type
                ParameterizedType pt = (ParameterizedType) type;
                if (pt.getRawType() instanceof Class
                        && Collection.class.isAssignableFrom((Class) pt.getRawType())) {
                    // is this rawtype a class and is this class some collection
                    Type generic = pt.getActualTypeArguments()[0];
                    if (generic instanceof Class && Entity.class.isAssignableFrom((Class) generic)) {
                        // is this collection generic an entity
                        return true;
                    }
                }
            }
        }
        return false;
    }

    @Override
    public boolean canWrite(Class<?> clazz, MediaType mediaType) {
        // this is rather ugly, would be great if we could get hold of the Type rather than class, so that we can check
        // for the generic type and decide upon this
        return MediaType.APPLICATION_JSON.equals(mediaType)
                && (Entity.class.isAssignableFrom(clazz) || Collection.class.isAssignableFrom(clazz));
    }
}