Browse Source

Merge pull request #1499 from rlindooren/SPR-15866-use-provided-mime-types

pull/1493/merge
Rossen Stoyanchev 7 years ago
parent
commit
bb327b90a6
  1. 10
      spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Decoder.java
  2. 4
      spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Encoder.java
  3. 20
      spring-web/src/main/java/org/springframework/http/codec/json/Jackson2CodecSupport.java
  4. 2
      spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonDecoder.java
  5. 2
      spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java
  6. 25
      spring-web/src/test/java/org/springframework/http/codec/json/Jackson2JsonDecoderTests.java
  7. 21
      spring-web/src/test/java/org/springframework/http/codec/json/Jackson2JsonEncoderTests.java

10
spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Decoder.java

@ -65,10 +65,10 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple @@ -65,10 +65,10 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple
@Override
public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) {
JavaType javaType = objectMapper().getTypeFactory().constructType(elementType.getType());
JavaType javaType = getObjectMapper().getTypeFactory().constructType(elementType.getType());
// Skip String: CharSequenceDecoder + "*/*" comes after
return (!CharSequence.class.isAssignableFrom(elementType.resolve(Object.class)) &&
objectMapper().canDeserialize(javaType) && supportsMimeType(mimeType));
getObjectMapper().canDeserialize(javaType) && supportsMimeType(mimeType));
}
@Override
@ -89,7 +89,7 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple @@ -89,7 +89,7 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple
private Flux<TokenBuffer> tokenize(Publisher<DataBuffer> input, boolean tokenizeArrayElements) {
try {
JsonFactory factory = objectMapper().getFactory();
JsonFactory factory = getObjectMapper().getFactory();
JsonParser parser = factory.createNonBlockingByteArrayParser();
Jackson2Tokenizer tokenizer = new Jackson2Tokenizer(parser, tokenizeArrayElements);
return Flux.from(input).flatMap(tokenizer).doFinally(t -> tokenizer.endOfInput());
@ -111,8 +111,8 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple @@ -111,8 +111,8 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple
Class<?> jsonView = (hints != null ? (Class<?>) hints.get(Jackson2CodecSupport.JSON_VIEW_HINT) : null);
ObjectReader reader = (jsonView != null ?
objectMapper().readerWithView(jsonView).forType(javaType) :
objectMapper().readerFor(javaType));
getObjectMapper().readerWithView(jsonView).forType(javaType) :
getObjectMapper().readerFor(javaType));
return tokens.map(tokenBuffer -> {
try {

4
spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Encoder.java

@ -81,7 +81,7 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple @@ -81,7 +81,7 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple
Class<?> clazz = elementType.resolve(Object.class);
return (Object.class == clazz) ||
!String.class.isAssignableFrom(elementType.resolve(clazz)) &&
objectMapper().canSerialize(clazz) && supportsMimeType(mimeType);
getObjectMapper().canSerialize(clazz) && supportsMimeType(mimeType);
}
@Override
@ -116,7 +116,7 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple @@ -116,7 +116,7 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple
JavaType javaType = getJavaType(elementType.getType(), null);
Class<?> jsonView = (hints != null ? (Class<?>) hints.get(Jackson2CodecSupport.JSON_VIEW_HINT) : null);
ObjectWriter writer = (jsonView != null ?
objectMapper().writerWithView(jsonView) : objectMapper().writer());
getObjectMapper().writerWithView(jsonView) : getObjectMapper().writer());
if (javaType.isContainerType()) {
writer = writer.forType(javaType);

20
spring-web/src/main/java/org/springframework/http/codec/json/Jackson2CodecSupport.java

@ -56,9 +56,10 @@ public abstract class Jackson2CodecSupport { @@ -56,9 +56,10 @@ public abstract class Jackson2CodecSupport {
private static final String JSON_VIEW_HINT_ERROR =
"@JsonView only supported for write hints with exactly 1 class argument: ";
protected static final List<MimeType> JSON_MIME_TYPES = Arrays.asList(
new MimeType("application", "json", StandardCharsets.UTF_8),
new MimeType("application", "*+json", StandardCharsets.UTF_8));
private static final List<MimeType> DEFAULT_MIME_TYPES = Collections.unmodifiableList(
Arrays.asList(
new MimeType("application", "json", StandardCharsets.UTF_8),
new MimeType("application", "*+json", StandardCharsets.UTF_8)));
private final ObjectMapper objectMapper;
@ -72,14 +73,23 @@ public abstract class Jackson2CodecSupport { @@ -72,14 +73,23 @@ public abstract class Jackson2CodecSupport {
protected Jackson2CodecSupport(ObjectMapper objectMapper, MimeType... mimeTypes) {
Assert.notNull(objectMapper, "ObjectMapper must not be null");
this.objectMapper = objectMapper;
this.mimeTypes = !ObjectUtils.isEmpty(mimeTypes) ? Arrays.asList(mimeTypes) : JSON_MIME_TYPES;
this.mimeTypes = !ObjectUtils.isEmpty(mimeTypes) ?
Collections.unmodifiableList(Arrays.asList(mimeTypes)) : DEFAULT_MIME_TYPES;
}
protected ObjectMapper objectMapper() {
public ObjectMapper getObjectMapper() {
return this.objectMapper;
}
/**
* Sub-classes should expose this as "decodable" or "encodable" mime types.
*/
protected List<MimeType> getMimeTypes() {
return this.mimeTypes;
}
protected boolean supportsMimeType(@Nullable MimeType mimeType) {
return (mimeType == null || this.mimeTypes.stream().anyMatch(m -> m.isCompatibleWith(mimeType)));
}

2
spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonDecoder.java

@ -42,6 +42,6 @@ public class Jackson2JsonDecoder extends AbstractJackson2Decoder { @@ -42,6 +42,6 @@ public class Jackson2JsonDecoder extends AbstractJackson2Decoder {
@Override
public List<MimeType> getDecodableMimeTypes() {
return JSON_MIME_TYPES;
return getMimeTypes();
}
}

2
spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java

@ -73,6 +73,6 @@ public class Jackson2JsonEncoder extends AbstractJackson2Encoder { @@ -73,6 +73,6 @@ public class Jackson2JsonEncoder extends AbstractJackson2Encoder {
@Override
public List<MimeType> getEncodableMimeTypes() {
return JSON_MIME_TYPES;
return getMimeTypes();
}
}

25
spring-web/src/test/java/org/springframework/http/codec/json/Jackson2JsonDecoderTests.java

@ -16,11 +16,12 @@ @@ -16,11 +16,12 @@
package org.springframework.http.codec.json;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Ignore;
import org.junit.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@ -32,11 +33,15 @@ import org.springframework.core.codec.DecodingException; @@ -32,11 +33,15 @@ import org.springframework.core.codec.DecodingException;
import org.springframework.core.io.buffer.AbstractDataBufferAllocatingTestCase;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.codec.Pojo;
import org.springframework.util.MimeType;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.springframework.core.ResolvableType.forClass;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.http.MediaType.APPLICATION_XML;
@ -63,6 +68,22 @@ public class Jackson2JsonDecoderTests extends AbstractDataBufferAllocatingTestCa @@ -63,6 +68,22 @@ public class Jackson2JsonDecoderTests extends AbstractDataBufferAllocatingTestCa
assertFalse(decoder.canDecode(forClass(Pojo.class), APPLICATION_XML));
}
@Test // SPR-15866
public void canDecodeWithProvidedMimeType() {
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
Jackson2JsonDecoder decoder = new Jackson2JsonDecoder(new ObjectMapper(), textJavascript);
assertEquals(Collections.singletonList(textJavascript), decoder.getDecodableMimeTypes());
}
@Test(expected = UnsupportedOperationException.class)
public void decodableMimeTypesIsImmutable() {
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
Jackson2JsonDecoder decoder = new Jackson2JsonDecoder(new ObjectMapper(), textJavascript);
decoder.getMimeTypes().add(new MimeType("text", "ecmascript"));
}
@Test
public void decodePojo() throws Exception {
Flux<DataBuffer> source = Flux.just(stringBuffer("{\"foo\": \"foofoo\", \"bar\": \"barbar\"}"));

21
spring-web/src/test/java/org/springframework/http/codec/json/Jackson2JsonEncoderTests.java

@ -16,16 +16,21 @@ @@ -16,16 +16,21 @@
package org.springframework.http.codec.json;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
import static java.util.Collections.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.springframework.http.MediaType.*;
import static org.springframework.http.codec.json.Jackson2JsonEncoder.*;
import static org.springframework.http.codec.json.JacksonViewBean.*;
import org.springframework.util.MimeType;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
@ -58,6 +63,22 @@ public class Jackson2JsonEncoderTests extends AbstractDataBufferAllocatingTestCa @@ -58,6 +63,22 @@ public class Jackson2JsonEncoderTests extends AbstractDataBufferAllocatingTestCa
assertTrue(this.encoder.canEncode(ResolvableType.NONE, null));
}
@Test // SPR-15866
public void canEncodeWithCustomMimeType() {
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
Jackson2JsonEncoder encoder = new Jackson2JsonEncoder(new ObjectMapper(), textJavascript);
assertEquals(Collections.singletonList(textJavascript), encoder.getEncodableMimeTypes());
}
@Test(expected = UnsupportedOperationException.class)
public void encodableMimeTypesIsImmutable() {
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
Jackson2JsonEncoder encoder = new Jackson2JsonEncoder(new ObjectMapper(), textJavascript);
encoder.getMimeTypes().add(new MimeType("text", "ecmascript"));
}
@Test
public void canNotEncode() {
assertFalse(this.encoder.canEncode(ResolvableType.forClass(String.class), null));

Loading…
Cancel
Save