001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.http.converter; 018 019import java.io.IOException; 020import java.nio.charset.Charset; 021 022import org.springframework.core.convert.ConversionService; 023import org.springframework.http.HttpInputMessage; 024import org.springframework.http.HttpOutputMessage; 025import org.springframework.http.MediaType; 026import org.springframework.util.Assert; 027 028/** 029 * An {@code HttpMessageConverter} that uses {@link StringHttpMessageConverter} 030 * for reading and writing content and a {@link ConversionService} for converting 031 * the String content to and from the target object type. 032 * 033 * <p>By default, this converter supports the media type {@code text/plain} only. 034 * This can be overridden through the {@link #setSupportedMediaTypes supportedMediaTypes} 035 * property. 036 * 037 * <p>A usage example: 038 * 039 * <pre class="code"> 040 * <bean class="org.springframework.http.converter.ObjectToStringHttpMessageConverter"> 041 * <constructor-arg> 042 * <bean class="org.springframework.context.support.ConversionServiceFactoryBean"/> 043 * </constructor-arg> 044 * </bean> 045 * </pre> 046 * 047 * @author <a href="mailto:dmitry.katsubo@gmail.com">Dmitry Katsubo</a> 048 * @author Rossen Stoyanchev 049 * @since 3.2 050 */ 051public class ObjectToStringHttpMessageConverter extends AbstractHttpMessageConverter<Object> { 052 053 private final ConversionService conversionService; 054 055 private final StringHttpMessageConverter stringHttpMessageConverter; 056 057 058 /** 059 * A constructor accepting a {@code ConversionService} to use to convert the 060 * (String) message body to/from the target class type. This constructor uses 061 * {@link StringHttpMessageConverter#DEFAULT_CHARSET} as the default charset. 062 * @param conversionService the conversion service 063 */ 064 public ObjectToStringHttpMessageConverter(ConversionService conversionService) { 065 this(conversionService, StringHttpMessageConverter.DEFAULT_CHARSET); 066 } 067 068 /** 069 * A constructor accepting a {@code ConversionService} as well as a default charset. 070 * @param conversionService the conversion service 071 * @param defaultCharset the default charset 072 */ 073 public ObjectToStringHttpMessageConverter(ConversionService conversionService, Charset defaultCharset) { 074 super(defaultCharset, MediaType.TEXT_PLAIN); 075 076 Assert.notNull(conversionService, "ConversionService is required"); 077 this.conversionService = conversionService; 078 this.stringHttpMessageConverter = new StringHttpMessageConverter(defaultCharset); 079 } 080 081 082 /** 083 * Indicates whether the {@code Accept-Charset} should be written to any outgoing request. 084 * <p>Default is {@code true}. 085 */ 086 public void setWriteAcceptCharset(boolean writeAcceptCharset) { 087 this.stringHttpMessageConverter.setWriteAcceptCharset(writeAcceptCharset); 088 } 089 090 091 @Override 092 public boolean canRead(Class<?> clazz, MediaType mediaType) { 093 return this.conversionService.canConvert(String.class, clazz) && canRead(mediaType); 094 } 095 096 @Override 097 public boolean canWrite(Class<?> clazz, MediaType mediaType) { 098 return this.conversionService.canConvert(clazz, String.class) && canWrite(mediaType); 099 } 100 101 @Override 102 protected boolean supports(Class<?> clazz) { 103 // should not be called, since we override canRead/Write 104 throw new UnsupportedOperationException(); 105 } 106 107 @Override 108 protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException { 109 String value = this.stringHttpMessageConverter.readInternal(String.class, inputMessage); 110 return this.conversionService.convert(value, clazz); 111 } 112 113 @Override 114 protected void writeInternal(Object obj, HttpOutputMessage outputMessage) throws IOException { 115 String value = this.conversionService.convert(obj, String.class); 116 this.stringHttpMessageConverter.writeInternal(value, outputMessage); 117 } 118 119 @Override 120 protected Long getContentLength(Object obj, MediaType contentType) { 121 String value = this.conversionService.convert(obj, String.class); 122 return this.stringHttpMessageConverter.getContentLength(value, contentType); 123 } 124 125}