Browse Source

Polishing

pull/25487/head
Rossen Stoyanchev 6 years ago
parent
commit
354635ede0
  1. 99
      spring-web/src/test/java/org/springframework/http/codec/json/Jackson2JsonDecoderTests.java
  2. 114
      spring-web/src/test/java/org/springframework/http/codec/json/Jackson2TokenizerTests.java

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

@ -20,6 +20,7 @@ import java.io.IOException; @@ -20,6 +20,7 @@ import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -47,12 +48,8 @@ import org.springframework.http.codec.json.JacksonViewBean.MyJacksonView3; @@ -47,12 +48,8 @@ import org.springframework.http.codec.json.JacksonViewBean.MyJacksonView3;
import org.springframework.util.MimeType;
import org.springframework.web.testfixture.xml.Pojo;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.springframework.core.ResolvableType.forClass;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.http.MediaType.APPLICATION_STREAM_JSON;
import static org.springframework.http.MediaType.APPLICATION_XML;
@ -79,12 +76,12 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD @@ -79,12 +76,12 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD
@Override
@Test
public void canDecode() {
assertThat(decoder.canDecode(forClass(Pojo.class), APPLICATION_JSON)).isTrue();
assertThat(decoder.canDecode(forClass(Pojo.class), APPLICATION_STREAM_JSON)).isTrue();
assertThat(decoder.canDecode(forClass(Pojo.class), null)).isTrue();
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), APPLICATION_JSON)).isTrue();
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), APPLICATION_STREAM_JSON)).isTrue();
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), null)).isTrue();
assertThat(decoder.canDecode(forClass(String.class), null)).isFalse();
assertThat(decoder.canDecode(forClass(Pojo.class), APPLICATION_XML)).isFalse();
assertThat(decoder.canDecode(ResolvableType.forClass(String.class), null)).isFalse();
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), APPLICATION_XML)).isFalse();
assertThat(this.decoder.canDecode(ResolvableType.forClass(Pojo.class),
new MediaType("application", "json", StandardCharsets.UTF_8))).isTrue();
assertThat(this.decoder.canDecode(ResolvableType.forClass(Pojo.class),
@ -133,7 +130,7 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD @@ -133,7 +130,7 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD
ResolvableType elementType = ResolvableType.forClassWithGenerics(List.class, Pojo.class);
testDecodeToMonoAll(input, elementType, step -> step
.expectNext(asList(new Pojo("f1", "b1"), new Pojo("f2", "b2")))
.expectNext(Arrays.asList(new Pojo("f1", "b1"), new Pojo("f2", "b2")))
.expectComplete()
.verify(), null, null);
}
@ -143,22 +140,23 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD @@ -143,22 +140,23 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD
public void decodeEmptyArrayToFlux() {
Flux<DataBuffer> input = Flux.from(stringBuffer("[]"));
testDecode(input, Pojo.class, step -> step.verifyComplete());
testDecode(input, Pojo.class, StepVerifier.LastStep::verifyComplete);
}
@Test
public void fieldLevelJsonView() {
Flux<DataBuffer> input = Flux.from(
stringBuffer("{\"withView1\" : \"with\", \"withView2\" : \"with\", \"withoutView\" : \"without\"}"));
ResolvableType elementType = forClass(JacksonViewBean.class);
Map<String, Object> hints = singletonMap(JSON_VIEW_HINT, MyJacksonView1.class);
Flux<DataBuffer> input = Flux.from(stringBuffer(
"{\"withView1\" : \"with\", \"withView2\" : \"with\", \"withoutView\" : \"without\"}"));
ResolvableType elementType = ResolvableType.forClass(JacksonViewBean.class);
Map<String, Object> hints = Collections.singletonMap(JSON_VIEW_HINT, MyJacksonView1.class);
testDecode(input, elementType, step -> step
.consumeNextWith(o -> {
JacksonViewBean b = (JacksonViewBean) o;
assertThat(b.getWithView1()).isEqualTo("with");
assertThat(b.getWithView2()).isNull();
assertThat(b.getWithoutView()).isNull();
.consumeNextWith(value -> {
JacksonViewBean bean = (JacksonViewBean) value;
assertThat(bean.getWithView1()).isEqualTo("with");
assertThat(bean.getWithView2()).isNull();
assertThat(bean.getWithoutView()).isNull();
}), null, hints);
}
@ -166,25 +164,24 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD @@ -166,25 +164,24 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD
public void classLevelJsonView() {
Flux<DataBuffer> input = Flux.from(stringBuffer(
"{\"withView1\" : \"with\", \"withView2\" : \"with\", \"withoutView\" : \"without\"}"));
ResolvableType elementType = forClass(JacksonViewBean.class);
Map<String, Object> hints = singletonMap(JSON_VIEW_HINT, MyJacksonView3.class);
ResolvableType elementType = ResolvableType.forClass(JacksonViewBean.class);
Map<String, Object> hints = Collections.singletonMap(JSON_VIEW_HINT, MyJacksonView3.class);
testDecode(input, elementType, step -> step
.consumeNextWith(o -> {
JacksonViewBean b = (JacksonViewBean) o;
assertThat(b.getWithoutView()).isEqualTo("without");
assertThat(b.getWithView1()).isNull();
assertThat(b.getWithView2()).isNull();
.consumeNextWith(value -> {
JacksonViewBean bean = (JacksonViewBean) value;
assertThat(bean.getWithoutView()).isEqualTo("without");
assertThat(bean.getWithView1()).isNull();
assertThat(bean.getWithView2()).isNull();
})
.verifyComplete(), null, hints);
}
@Test
public void invalidData() {
Flux<DataBuffer> input =
Flux.from(stringBuffer("{\"foofoo\": \"foofoo\", \"barbar\": \"barbar\""));
testDecode(input, Pojo.class, step -> step
.verifyError(DecodingException.class));
Flux<DataBuffer> input = Flux.from(stringBuffer("{\"foofoo\": \"foofoo\", \"barbar\": \"barbar\""));
testDecode(input, Pojo.class, step -> step.verifyError(DecodingException.class));
}
@Test // gh-22042
@ -197,10 +194,9 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD @@ -197,10 +194,9 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD
@Test
public void noDefaultConstructor() {
Flux<DataBuffer> input =
Flux.from(stringBuffer("{\"property1\":\"foo\",\"property2\":\"bar\"}"));
ResolvableType elementType = forClass(BeanWithNoDefaultConstructor.class);
Flux<Object> flux = new Jackson2JsonDecoder().decode(input, elementType, null, emptyMap());
Flux<DataBuffer> input = Flux.from(stringBuffer("{\"property1\":\"foo\",\"property2\":\"bar\"}"));
ResolvableType elementType = ResolvableType.forClass(BeanWithNoDefaultConstructor.class);
Flux<Object> flux = new Jackson2JsonDecoder().decode(input, elementType, null, Collections.emptyMap());
StepVerifier.create(flux).verifyError(CodecException.class);
}
@ -228,9 +224,10 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD @@ -228,9 +224,10 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD
@SuppressWarnings("unchecked")
public void decodeNonUtf8Encoding() {
Mono<DataBuffer> input = stringBuffer("{\"foo\":\"bar\"}", StandardCharsets.UTF_16);
ResolvableType type = ResolvableType.forType(new ParameterizedTypeReference<Map<String, String>>() {});
testDecode(input, ResolvableType.forType(new ParameterizedTypeReference<Map<String, String>>() {}),
step -> step.assertNext(o -> assertThat((Map<String, String>) o).containsEntry("foo", "bar"))
testDecode(input, type, step -> step
.assertNext(value -> assertThat((Map<String, String>) value).containsEntry("foo", "bar"))
.verifyComplete(),
MediaType.parseMediaType("application/json; charset=utf-16"),
null);
@ -239,12 +236,11 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD @@ -239,12 +236,11 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD
@Test
@SuppressWarnings("unchecked")
public void decodeNonUnicode() {
Flux<DataBuffer> input = Flux.concat(
stringBuffer("{\"føø\":\"bår\"}", StandardCharsets.ISO_8859_1)
);
Flux<DataBuffer> input = Flux.concat(stringBuffer("{\"føø\":\"bår\"}", StandardCharsets.ISO_8859_1));
ResolvableType type = ResolvableType.forType(new ParameterizedTypeReference<Map<String, String>>() {});
testDecode(input, ResolvableType.forType(new ParameterizedTypeReference<Map<String, String>>() {}),
step -> step.assertNext(o -> assertThat((Map<String, String>) o).containsEntry("føø", "bår"))
testDecode(input, type, step -> step
.assertNext(o -> assertThat((Map<String, String>) o).containsEntry("føø", "bår"))
.verifyComplete(),
MediaType.parseMediaType("application/json; charset=iso-8859-1"),
null);
@ -254,9 +250,10 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD @@ -254,9 +250,10 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD
@SuppressWarnings("unchecked")
public void decodeMonoNonUtf8Encoding() {
Mono<DataBuffer> input = stringBuffer("{\"foo\":\"bar\"}", StandardCharsets.UTF_16);
ResolvableType type = ResolvableType.forType(new ParameterizedTypeReference<Map<String, String>>() {});
testDecodeToMono(input, ResolvableType.forType(new ParameterizedTypeReference<Map<String, String>>() {}),
step -> step.assertNext(o -> assertThat((Map<String, String>) o).containsEntry("foo", "bar"))
testDecodeToMono(input, type, step -> step
.assertNext(value -> assertThat((Map<String, String>) value).containsEntry("foo", "bar"))
.verifyComplete(),
MediaType.parseMediaType("application/json; charset=utf-16"),
null);
@ -265,12 +262,11 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD @@ -265,12 +262,11 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD
@Test
@SuppressWarnings("unchecked")
public void decodeAscii() {
Flux<DataBuffer> input = Flux.concat(
stringBuffer("{\"foo\":\"bar\"}", StandardCharsets.US_ASCII)
);
Flux<DataBuffer> input = Flux.concat(stringBuffer("{\"foo\":\"bar\"}", StandardCharsets.US_ASCII));
ResolvableType type = ResolvableType.forType(new ParameterizedTypeReference<Map<String, String>>() {});
testDecode(input, ResolvableType.forType(new ParameterizedTypeReference<Map<String, String>>() {}),
step -> step.assertNext(o -> assertThat((Map<String, String>) o).containsEntry("foo", "bar"))
testDecode(input, type, step -> step
.assertNext(value -> assertThat((Map<String, String>) value).containsEntry("foo", "bar"))
.verifyComplete(),
MediaType.parseMediaType("application/json; charset=us-ascii"),
null);
@ -291,7 +287,6 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD @@ -291,7 +287,6 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD
}
@SuppressWarnings("unused")
private static class BeanWithNoDefaultConstructor {
private final String property1;
@ -314,7 +309,7 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD @@ -314,7 +309,7 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD
@JsonDeserialize(using = Deserializer.class)
public static class TestObject {
private static class TestObject {
private int test;
@ -327,7 +322,7 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD @@ -327,7 +322,7 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD
}
public static class Deserializer extends StdDeserializer<TestObject> {
private static class Deserializer extends StdDeserializer<TestObject> {
private static final long serialVersionUID = 1L;

114
spring-web/src/test/java/org/springframework/http/codec/json/Jackson2TokenizerTests.java

@ -72,46 +72,43 @@ public class Jackson2TokenizerTests extends AbstractLeakCheckingTests { @@ -72,46 +72,43 @@ public class Jackson2TokenizerTests extends AbstractLeakCheckingTests {
singletonList("{\"foo\": \"foofoo\", \"bar\": \"barbar\"}"), false);
testTokenize(
asList("{\"foo\": \"foofoo\"",
", \"bar\": \"barbar\"}"),
asList(
"{\"foo\": \"foofoo\"",
", \"bar\": \"barbar\"}"
),
singletonList("{\"foo\":\"foofoo\",\"bar\":\"barbar\"}"), false);
testTokenize(
singletonList("[" +
"{\"foo\": \"foofoo\", \"bar\": \"barbar\"}," +
"{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}]"),
singletonList("[" +
"{\"foo\": \"foofoo\", \"bar\": \"barbar\"}," +
"{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}]"), false);
singletonList("[{\"foo\": \"foofoo\", \"bar\": \"barbar\"},{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}]"),
singletonList("[{\"foo\": \"foofoo\", \"bar\": \"barbar\"},{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}]"),
false);
testTokenize(
singletonList("[{\"foo\": \"bar\"},{\"foo\": \"baz\"}]"),
singletonList("[{\"foo\": \"bar\"},{\"foo\": \"baz\"}]"), false);
testTokenize(
asList("[" +
"{\"foo\": \"foofoo\", \"bar\"", ": \"barbar\"}," +
"{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}]"),
singletonList("[" +
"{\"foo\": \"foofoo\", \"bar\": \"barbar\"}," +
"{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}]"), false);
asList(
"[{\"foo\": \"foofoo\", \"bar\"",
": \"barbar\"},{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}]"
),
singletonList("[{\"foo\": \"foofoo\", \"bar\": \"barbar\"},{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}]"),
false);
testTokenize(
asList("[",
asList(
"[",
"{\"id\":1,\"name\":\"Robert\"}", ",",
"{\"id\":2,\"name\":\"Raide\"}", ",",
"{\"id\":3,\"name\":\"Ford\"}", "]"),
singletonList("[" +
"{\"id\":1,\"name\":\"Robert\"}," +
"{\"id\":2,\"name\":\"Raide\"}," +
"{\"id\":3,\"name\":\"Ford\"}]"), false);
"{\"id\":3,\"name\":\"Ford\"}", "]"
),
singletonList("[{\"id\":1,\"name\":\"Robert\"},{\"id\":2,\"name\":\"Raide\"},{\"id\":3,\"name\":\"Ford\"}]"),
false);
// SPR-16166: top-level JSON values
testTokenize(asList("\"foo", "bar\""),singletonList("\"foobar\""), false);
testTokenize(asList("12", "34"),singletonList("1234"), false);
testTokenize(asList("12.", "34"),singletonList("12.34"), false);
testTokenize(asList("\"foo", "bar\""), singletonList("\"foobar\""), false);
testTokenize(asList("12", "34"), singletonList("1234"), false);
testTokenize(asList("12.", "34"), singletonList("12.34"), false);
// note that we do not test for null, true, or false, which are also valid top-level values,
// but are unsupported by JSONassert
@ -124,20 +121,27 @@ public class Jackson2TokenizerTests extends AbstractLeakCheckingTests { @@ -124,20 +121,27 @@ public class Jackson2TokenizerTests extends AbstractLeakCheckingTests {
singletonList("{\"foo\": \"foofoo\", \"bar\": \"barbar\"}"), true);
testTokenize(
asList("{\"foo\": \"foofoo\"", ", \"bar\": \"barbar\"}"),
asList(
"{\"foo\": \"foofoo\"",
", \"bar\": \"barbar\"}"
),
singletonList("{\"foo\":\"foofoo\",\"bar\":\"barbar\"}"), true);
testTokenize(
singletonList("[" +
"{\"foo\": \"foofoo\", \"bar\": \"barbar\"}," +
"{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}]"),
singletonList("[{\"foo\": \"foofoo\", \"bar\": \"barbar\"},{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}]"),
asList(
"{\"foo\": \"foofoo\", \"bar\": \"barbar\"}",
"{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}"), true);
"{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}"
),
true);
testTokenize(
singletonList("[{\"foo\": \"bar\"},{\"foo\": \"baz\"}]"),
asList("{\"foo\": \"bar\"}", "{\"foo\": \"baz\"}"), true);
asList(
"{\"foo\": \"bar\"}",
"{\"foo\": \"baz\"}"
),
true);
// SPR-15803: nested array
testTokenize(
@ -149,7 +153,9 @@ public class Jackson2TokenizerTests extends AbstractLeakCheckingTests { @@ -149,7 +153,9 @@ public class Jackson2TokenizerTests extends AbstractLeakCheckingTests {
asList(
"{\"id\":\"0\",\"start\":[-999999999,1,1],\"end\":[999999999,12,31]}",
"{\"id\":\"1\",\"start\":[-999999999,1,1],\"end\":[999999999,12,31]}",
"{\"id\":\"2\",\"start\":[-999999999,1,1],\"end\":[999999999,12,31]}"), true);
"{\"id\":\"2\",\"start\":[-999999999,1,1],\"end\":[999999999,12,31]}"
),
true);
// SPR-15803: nested array, no top-level array
testTokenize(
@ -157,31 +163,35 @@ public class Jackson2TokenizerTests extends AbstractLeakCheckingTests { @@ -157,31 +163,35 @@ public class Jackson2TokenizerTests extends AbstractLeakCheckingTests {
singletonList("{\"speakerIds\":[\"tastapod\"],\"language\":\"ENGLISH\"}"), true);
testTokenize(
asList("[" +
"{\"foo\": \"foofoo\", \"bar\"", ": \"barbar\"}," +
"{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}]"),
asList(
"[{\"foo\": \"foofoo\", \"bar\"",
": \"barbar\"},{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}]"
),
asList(
"{\"foo\": \"foofoo\", \"bar\": \"barbar\"}",
"{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}"), true);
testTokenize(
asList("[",
asList(
"[",
"{\"id\":1,\"name\":\"Robert\"}",
",",
"{\"id\":2,\"name\":\"Raide\"}",
",",
"{\"id\":3,\"name\":\"Ford\"}",
"]"),
asList("{\"id\":1,\"name\":\"Robert\"}",
"]"
),
asList(
"{\"id\":1,\"name\":\"Robert\"}",
"{\"id\":2,\"name\":\"Raide\"}",
"{\"id\":3,\"name\":\"Ford\"}"), true);
"{\"id\":3,\"name\":\"Ford\"}"
),
true);
// SPR-16166: top-level JSON values
testTokenize(asList("\"foo", "bar\""),singletonList("\"foobar\""), true);
testTokenize(asList("12", "34"),singletonList("1234"), true);
testTokenize(asList("12.", "34"),singletonList("12.34"), true);
testTokenize(asList("\"foo", "bar\""), singletonList("\"foobar\""), true);
testTokenize(asList("12", "34"), singletonList("1234"), true);
testTokenize(asList("12.", "34"), singletonList("12.34"), true);
// SPR-16407
testTokenize(asList("[1", ",2,", "3]"), asList("1", "2", "3"), true);
@ -202,12 +212,13 @@ public class Jackson2TokenizerTests extends AbstractLeakCheckingTests { @@ -202,12 +212,13 @@ public class Jackson2TokenizerTests extends AbstractLeakCheckingTests {
@Test
public void testLimit() {
List<String> source = asList("[",
List<String> source = asList(
"[",
"{", "\"id\":1,\"name\":\"Dan\"", "},",
"{", "\"id\":2,\"name\":\"Ron\"", "},",
"{", "\"id\":3,\"name\":\"Bartholomew\"", "}",
"]");
"]"
);
String expected = String.join("", source);
int maxInMemorySize = expected.length();
@ -223,11 +234,13 @@ public class Jackson2TokenizerTests extends AbstractLeakCheckingTests { @@ -223,11 +234,13 @@ public class Jackson2TokenizerTests extends AbstractLeakCheckingTests {
@Test
public void testLimitTokenized() {
List<String> source = asList("[",
List<String> source = asList(
"[",
"{", "\"id\":1, \"name\":\"Dan\"", "},",
"{", "\"id\":2, \"name\":\"Ron\"", "},",
"{", "\"id\":3, \"name\":\"Bartholomew\"", "}",
"]");
"]"
);
String expected = "{\"id\":3,\"name\":\"Bartholomew\"}";
int maxInMemorySize = expected.length();
@ -271,7 +284,8 @@ public class Jackson2TokenizerTests extends AbstractLeakCheckingTests { @@ -271,7 +284,8 @@ public class Jackson2TokenizerTests extends AbstractLeakCheckingTests {
@ValueSource(booleans = {false, true})
public void useBigDecimalForFloats(boolean useBigDecimalForFloats) {
Flux<DataBuffer> source = Flux.just(stringBuffer("1E+2"));
Flux<TokenBuffer> tokens = Jackson2Tokenizer.tokenize(source, this.jsonFactory, this.objectMapper, false, useBigDecimalForFloats, -1);
Flux<TokenBuffer> tokens = Jackson2Tokenizer.tokenize(
source, this.jsonFactory, this.objectMapper, false, useBigDecimalForFloats, -1);
StepVerifier.create(tokens)
.assertNext(tokenBuffer -> {

Loading…
Cancel
Save