Skip to content

Commit 9e2d54f

Browse files
committed
Support json view with JacksonTester
Closes gh-8672
1 parent e1f7277 commit 9e2d54f

File tree

7 files changed

+261
-5
lines changed

7 files changed

+261
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.test.autoconfigure.json;
18+
19+
import com.fasterxml.jackson.annotation.JsonView;
20+
21+
import org.springframework.util.ObjectUtils;
22+
23+
/**
24+
* Example object to read/write as JSON with view
25+
*
26+
* @author Madhura Bhave
27+
*/
28+
public class ExampleJsonObjectWithView {
29+
30+
@JsonView(TestView.class)
31+
private String value;
32+
33+
private int id;
34+
35+
public String getValue() {
36+
return this.value;
37+
}
38+
39+
public void setValue(String value) {
40+
this.value = value;
41+
}
42+
43+
public int getId() {
44+
return this.id;
45+
}
46+
47+
public void setId(int id) {
48+
this.id = id;
49+
}
50+
51+
@Override
52+
public int hashCode() {
53+
return 0;
54+
}
55+
56+
@Override
57+
public boolean equals(Object obj) {
58+
if (obj == null || obj.getClass() != getClass()) {
59+
return false;
60+
}
61+
ExampleJsonObjectWithView other = (ExampleJsonObjectWithView) obj;
62+
return ObjectUtils.nullSafeEquals(this.value, other.value)
63+
&& ObjectUtils.nullSafeEquals(this.id, other.id);
64+
}
65+
66+
@Override
67+
public String toString() {
68+
return this.value + " " + this.id;
69+
}
70+
71+
static class TestView {
72+
73+
}
74+
75+
}
76+

spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestIntegrationTests.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.springframework.boot.test.json.BasicJsonTester;
2424
import org.springframework.boot.test.json.GsonTester;
2525
import org.springframework.boot.test.json.JacksonTester;
26+
import org.springframework.boot.test.json.JsonContent;
2627
import org.springframework.test.context.junit4.SpringRunner;
2728

2829
import static org.assertj.core.api.Assertions.assertThat;
@@ -42,6 +43,9 @@ public class JsonTestIntegrationTests {
4243
@Autowired
4344
private JacksonTester<ExampleBasicObject> jacksonBasicJson;
4445

46+
@Autowired
47+
private JacksonTester<ExampleJsonObjectWithView> jacksonWithViewJson;
48+
4549
@Autowired
4650
private JacksonTester<ExampleCustomObject> jacksonCustomJson;
4751

@@ -73,4 +77,14 @@ public void gson() throws Exception {
7377
assertThat(this.gsonJson.write(object)).isEqualToJson("example.json");
7478
}
7579

80+
@Test
81+
public void customView() throws Exception {
82+
ExampleJsonObjectWithView object = new ExampleJsonObjectWithView();
83+
object.setValue("spring");
84+
JsonContent<ExampleJsonObjectWithView> content = this.jacksonWithViewJson
85+
.forView(ExampleJsonObjectWithView.TestView.class)
86+
.write(object);
87+
assertThat(content).doesNotHaveJsonPathValue("id");
88+
assertThat(content).isEqualToJson("example.json");
89+
}
7690
}

spring-boot-test/src/main/java/org/springframework/boot/test/json/AbstractJsonMarshalTester.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ protected final ResolvableType getType() {
113113
return this.type;
114114
}
115115

116+
protected final Class<?> getResourceLoadClass() {
117+
return this.resourceLoadClass;
118+
}
119+
116120
/**
117121
* Return {@link JsonContent} from writing the specific value.
118122
* @param value the value to write

spring-boot-test/src/main/java/org/springframework/boot/test/json/JacksonTester.java

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
import com.fasterxml.jackson.databind.JavaType;
2424
import com.fasterxml.jackson.databind.ObjectMapper;
25+
import com.fasterxml.jackson.databind.ObjectReader;
26+
import com.fasterxml.jackson.databind.ObjectWriter;
2527

2628
import org.springframework.beans.factory.ObjectFactory;
2729
import org.springframework.core.ResolvableType;
@@ -53,12 +55,15 @@
5355
*
5456
* @param <T> the type under test
5557
* @author Phillip Webb
58+
* @author Madhura Bhave
5659
* @since 1.4.0
5760
*/
5861
public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
5962

6063
private final ObjectMapper objectMapper;
6164

65+
private Class<?> view;
66+
6267
/**
6368
* Create a new {@link JacksonTester} instance.
6469
* @param objectMapper the Jackson object mapper
@@ -76,25 +81,47 @@ protected JacksonTester(ObjectMapper objectMapper) {
7681
*/
7782
public JacksonTester(Class<?> resourceLoadClass, ResolvableType type,
7883
ObjectMapper objectMapper) {
84+
this(resourceLoadClass, type, objectMapper, null);
85+
}
86+
87+
public JacksonTester(Class<?> resourceLoadClass, ResolvableType type,
88+
ObjectMapper objectMapper, Class<?> view) {
7989
super(resourceLoadClass, type);
8090
Assert.notNull(objectMapper, "ObjectMapper must not be null");
8191
this.objectMapper = objectMapper;
92+
this.view = view;
8293
}
8394

8495
@Override
8596
protected T readObject(InputStream inputStream, ResolvableType type)
8697
throws IOException {
87-
return this.objectMapper.readValue(inputStream, getType(type));
98+
return getObjectReader(type).readValue(inputStream);
8899
}
89100

90101
@Override
91102
protected T readObject(Reader reader, ResolvableType type) throws IOException {
92-
return this.objectMapper.readerFor(getType(type)).readValue(reader);
103+
return getObjectReader(type).readValue(reader);
104+
}
105+
106+
private ObjectReader getObjectReader(ResolvableType type) {
107+
ObjectReader objectReader = this.objectMapper.readerFor(getType(type));
108+
if (this.view != null) {
109+
return objectReader.withView(this.view);
110+
}
111+
return objectReader;
93112
}
94113

95114
@Override
96115
protected String writeObject(T value, ResolvableType type) throws IOException {
97-
return this.objectMapper.writerFor(getType(type)).writeValueAsString(value);
116+
return getObjectWriter(type).writeValueAsString(value);
117+
}
118+
119+
private ObjectWriter getObjectWriter(ResolvableType type) {
120+
ObjectWriter objectWriter = this.objectMapper.writerFor(getType(type));
121+
if (this.view != null) {
122+
return objectWriter.withView(this.view);
123+
}
124+
return objectWriter;
98125
}
99126

100127
private JavaType getType(ResolvableType type) {
@@ -124,6 +151,16 @@ public static void initFields(Object testInstance,
124151
new JacksonFieldInitializer().initFields(testInstance, objectMapperFactory);
125152
}
126153

154+
/**
155+
* Returns a new instance of {@link JacksonTester} with the view
156+
* that should be used for json serialization/deserialization.
157+
* @param view the view class
158+
* @return the new instance
159+
*/
160+
public JacksonTester<T> forView(Class<?> view) {
161+
return new JacksonTester<T>(this.getResourceLoadClass(), this.getType(), this.objectMapper, view);
162+
}
163+
127164
/**
128165
* {@link FieldInitializer} for Jackson.
129166
*/

spring-boot-test/src/test/java/org/springframework/boot/test/json/ExampleObject.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,4 @@ public String toString() {
6464
}
6565

6666
}
67+
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.test.json;
18+
19+
import com.fasterxml.jackson.annotation.JsonView;
20+
21+
import org.springframework.util.ObjectUtils;
22+
23+
/**
24+
* Example object used for serialization/deserialization with view.
25+
*
26+
* @author Madhura Bhave
27+
*/
28+
public class ExampleObjectWithView {
29+
30+
@JsonView(TestView.class)
31+
private String name;
32+
33+
private int age;
34+
35+
public String getName() {
36+
return this.name;
37+
}
38+
39+
public void setName(String name) {
40+
this.name = name;
41+
}
42+
43+
public int getAge() {
44+
return this.age;
45+
}
46+
47+
public void setAge(int age) {
48+
this.age = age;
49+
}
50+
51+
@Override
52+
public int hashCode() {
53+
return 0;
54+
}
55+
56+
@Override
57+
public boolean equals(Object obj) {
58+
if (obj == null || obj.getClass() != getClass()) {
59+
return false;
60+
}
61+
ExampleObjectWithView other = (ExampleObjectWithView) obj;
62+
return ObjectUtils.nullSafeEquals(this.name, other.name)
63+
&& ObjectUtils.nullSafeEquals(this.age, other.age);
64+
}
65+
66+
@Override
67+
public String toString() {
68+
return this.name + " " + this.age;
69+
}
70+
71+
static class TestView {
72+
73+
}
74+
75+
}

spring-boot-test/src/test/java/org/springframework/boot/test/json/JacksonTesterIntegrationTests.java

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,19 @@
1616

1717
package org.springframework.boot.test.json;
1818

19+
import java.io.Reader;
20+
import java.io.StringReader;
1921
import java.util.LinkedHashMap;
2022
import java.util.List;
2123
import java.util.Map;
2224

25+
import com.fasterxml.jackson.databind.MapperFeature;
2326
import com.fasterxml.jackson.databind.ObjectMapper;
2427
import org.junit.Before;
2528
import org.junit.Test;
2629

30+
import org.springframework.core.io.ByteArrayResource;
31+
2732
import static org.assertj.core.api.Assertions.assertThat;
2833

2934
/**
@@ -33,18 +38,27 @@
3338
*/
3439
public class JacksonTesterIntegrationTests {
3540

41+
private JacksonTester<ExampleObject> simpleJson;
42+
43+
private JacksonTester<ExampleObjectWithView> jsonWithView;
44+
3645
private JacksonTester<List<ExampleObject>> listJson;
3746

3847
private JacksonTester<Map<String, Integer>> mapJson;
3948

49+
private ObjectMapper objectMapper;
50+
51+
private static final String JSON = "{\"name\":\"Spring\",\"age\":123}";
52+
4053
@Before
4154
public void setup() {
42-
JacksonTester.initFields(this, new ObjectMapper());
55+
this.objectMapper = new ObjectMapper();
56+
JacksonTester.initFields(this, this.objectMapper);
4357
}
4458

4559
@Test
4660
public void typicalListTest() throws Exception {
47-
String example = "[{\"name\":\"Spring\",\"age\":123}]";
61+
String example = "[" + JSON + "]";
4862
assertThat(this.listJson.parse(example)).asList().hasSize(1);
4963
assertThat(this.listJson.parse(example).getObject().get(0).getName())
5064
.isEqualTo("Spring");
@@ -59,4 +73,39 @@ public void typicalMapTest() throws Exception {
5973
.isEqualTo(1);
6074
}
6175

76+
@Test
77+
public void writeWithView() throws Exception {
78+
this.objectMapper.disable(MapperFeature.DEFAULT_VIEW_INCLUSION);
79+
ExampleObjectWithView object = new ExampleObjectWithView();
80+
object.setName("Spring");
81+
object.setAge(123);
82+
JsonContent<ExampleObjectWithView> content = this.jsonWithView.forView(
83+
ExampleObjectWithView.TestView.class).write(object);
84+
assertThat(content).extractingJsonPathStringValue("@.name")
85+
.isEqualTo("Spring");
86+
assertThat(content).doesNotHaveJsonPathValue("age");
87+
}
88+
89+
@Test
90+
public void readWithResourceAndView() throws Exception {
91+
this.objectMapper.disable(MapperFeature.DEFAULT_VIEW_INCLUSION);
92+
ByteArrayResource resource = new ByteArrayResource(JSON.getBytes());
93+
ObjectContent<ExampleObjectWithView> content = this.jsonWithView.forView(
94+
ExampleObjectWithView.TestView.class).read(resource);
95+
assertThat(content.getObject().getName())
96+
.isEqualTo("Spring");
97+
assertThat(content.getObject().getAge()).isEqualTo(0);
98+
}
99+
100+
@Test
101+
public void readWithReaderAndView() throws Exception {
102+
this.objectMapper.disable(MapperFeature.DEFAULT_VIEW_INCLUSION);
103+
Reader reader = new StringReader(JSON);
104+
ObjectContent<ExampleObjectWithView> content = this.jsonWithView.forView(
105+
ExampleObjectWithView.TestView.class).read(reader);
106+
assertThat(content.getObject().getName())
107+
.isEqualTo("Spring");
108+
assertThat(content.getObject().getAge()).isEqualTo(0);
109+
}
110+
62111
}

0 commit comments

Comments
 (0)