Java tutorial
/** * 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)); } }