1 package com.atlassian.plugins.rest.common.json;
2
3 import com.google.common.base.Function;
4 import com.google.common.collect.Iterables;
5 import com.google.common.collect.Lists;
6 import org.codehaus.jackson.annotate.JsonProperty;
7 import org.codehaus.jackson.map.annotate.JsonSerialize;
8 import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
9 import org.codehaus.jackson.map.ser.std.IterableSerializer;
10 import org.junit.Before;
11 import org.junit.Test;
12
13 import javax.annotation.Nullable;
14 import javax.xml.bind.JAXBException;
15 import javax.xml.bind.annotation.XmlElement;
16 import javax.xml.bind.annotation.XmlRootElement;
17 import java.net.URI;
18 import java.util.Arrays;
19 import java.util.Collections;
20 import java.util.Iterator;
21 import java.util.List;
22
23 import static com.google.common.collect.ImmutableList.copyOf;
24 import static org.apache.commons.lang.SystemUtils.LINE_SEPARATOR;
25 import static org.junit.Assert.assertEquals;
26
27 public class DefaultJaxbJsonMarshallerTest {
28 private JaxbJsonMarshaller marshaller;
29
30 @Before
31 public void setUp() {
32 marshaller = DefaultJaxbJsonMarshaller.builder().build();
33 }
34
35 @Test
36 public void testMarshalBoolean() throws JAXBException {
37 assertEquals("true", marshaller.marshal(Boolean.TRUE));
38 }
39
40 @Test
41 public void testMarshalUrlWithSpaces() throws Exception {
42 assertEquals("\"https://user:paswd@a.b.c:8443/path/to%20file/on%20disk/aaa%20bbb%20ccc.p%20d%20f?q%20u%20e%20r%20y#frag%20ment\"",
43 marshaller.marshal(new URI("https", "user:paswd", "a.b.c", 8443, "/path/to file/on disk/aaa bbb ccc.p d f", "q u e r y", "frag ment")));
44 }
45
46 @Test
47 public void testMarshalInteger() throws JAXBException {
48 assertEquals("2", marshaller.marshal(Integer.valueOf(2)));
49 }
50
51 @Test
52 public void testMarshalGuavaIterable() throws JAXBException {
53 assertEquals("[\"ad\",\"bd\",\"cd\"]", marshaller.marshal(
54 Iterables.transform(Arrays.asList(new String[]{"a", "b", "c"}), new Function<String, String>() {
55 @Nullable
56 @Override
57 public String apply(final String input) {
58 return input + "d";
59 }
60 })
61 ));
62 }
63
64 @Test
65 public void testMarshalEmptyGuavaIterable() throws JAXBException {
66 assertEquals("[]", marshaller.marshal(Iterables.transform(Lists.<String>newLinkedList(), new Function<String, String>() {
67 @Nullable
68 @Override
69 public String apply(final String input) {
70 return input + "d";
71 }
72 })
73 ));
74 }
75
76 static class JsonBeanWithIterable {
77 private final Iterable<String> strings;
78
79 public JsonBeanWithIterable(Iterable<String> strings) {
80 this.strings = strings;
81 }
82
83 @JsonProperty
84 public Iterable<String> getStrings() {
85 return strings;
86 }
87 }
88
89 @Test
90 public void testMarshalEmptyGuavaIterableInObject() throws JAXBException {
91 assertEquals("{\"strings\":[]}", marshaller.marshal(new JsonBeanWithIterable(Iterables.transform(Lists.<String>newLinkedList(), new Function<String, String>() {
92 @Nullable
93 @Override
94 public String apply(final String input) {
95 return input + "d";
96 }
97 })
98 )));
99 }
100
101 @Test
102 public void testMarshalNotEmptyGuavaIterableInObject() throws JAXBException {
103 assertEquals("{\"strings\":[\"testd\"]}", marshaller.marshal(new JsonBeanWithIterable(Iterables.transform(Arrays.asList(new String[]{"test"}), new Function<String, String>() {
104 @Nullable
105 @Override
106 public String apply(final String input) {
107 return input + "d";
108 }
109 })
110 )));
111 }
112
113 static class IterableBean implements Iterable<String> {
114 @JsonProperty
115 private long id;
116
117 @JsonProperty
118 private List<String> tabs;
119
120 public IterableBean(final long id, final Iterable<String> tabs) {
121 this.id = id;
122 this.tabs = copyOf(tabs);
123 }
124
125 public long getId() {
126 return id;
127 }
128
129 public List<String> getTabs() {
130 return tabs;
131 }
132
133 @Override
134 public Iterator<String> iterator() {
135 return getTabs().iterator();
136 }
137 }
138
139 @Test
140 public void testMarshalIterableBean() {
141 assertEquals("{\"id\":1,\"tabs\":[\"tab1\",\"tab2\"]}", marshaller.marshal(
142 new IterableBean(1, Lists.newArrayList("tab1", "tab2"))));
143 }
144
145 @Test
146 public void testMarshalString() throws JAXBException {
147 assertEquals("\"foobar\"", marshaller.marshal("foobar"));
148 }
149
150 @Test
151 public void testMarshalMap() throws JAXBException {
152 assertEquals("{\"foo\":\"bar\"}", marshaller.marshal(Collections.singletonMap("foo", "bar")));
153 }
154
155 @Test
156 public void testMarshalList() throws JAXBException {
157 assertEquals("[\"foo\",\"bar\"]", marshaller.marshal(Arrays.asList("foo", "bar")));
158 }
159
160 @Test
161 public void testMarshalObjectWithMember() throws Exception {
162 assertEquals("{\"string\":\"foo\"}", marshaller.marshal(new ObjectWithMember("foo")));
163 }
164
165 @Test
166 public void testMarshalObjectWithNullMember() throws Exception {
167 assertEquals("{}", marshaller.marshal(new ObjectWithMember(null)));
168 }
169
170 @Test
171 public void testMarshalObjectWithMemberMissingAnnotation() throws Exception {
172 assertEquals("{}", marshaller.marshal(new ObjectWithMemberMissingAnnotation("foo")));
173 }
174
175 @Test
176 public void testMarshalObjectWithMemberWithRenaming() throws Exception {
177 assertEquals("{\"str\":\"foo\"}", marshaller.marshal(new ObjectWithMemberWithRenaming("foo")));
178 }
179
180 @Test
181 public void marshalCanPrettyPrint() throws Exception {
182 marshaller = DefaultJaxbJsonMarshaller.builder().prettyPrint(true).build();
183 assertEquals("{" + LINE_SEPARATOR + " \"str\" : \"foo\"" + LINE_SEPARATOR + "}", marshaller.marshal(new ObjectWithMemberWithRenaming("foo")));
184 }
185
186 @Test
187 public void testMarshalObjectWithJsonAnnotatedPropertyNull() throws Exception {
188 assertEquals("Default behaviour with @JsonProperty annotations should exclude null members",
189 "{}", marshaller.marshal(new JsonBeanInclusionDefault(null)));
190 }
191
192 @Test
193 public void testMarshalObjectWithJsonSerializeAnnotationButNoExplicitInclusionMeansAlways() throws Exception {
194 assertEquals("Behaviour with @JsonSerialize includes non-null members",
195 "{\"name\":null}", marshaller.marshal(new JsonBeanWithAnnotationButNoExplicitInclusion(null)));
196 }
197
198 @Test
199 public void testMarshalObjectWithJsonAnnotatedPropertyNullAndAlwaysInclusion() throws Exception {
200 assertEquals("If we ask for null members to always be included they should be in the result",
201 "{\"name\":null}", marshaller.marshal(new JsonBeanInclusionAlways(null)));
202 }
203
204 @Test
205 public void testMarshalObjectWithJsonAnnotatedPropertyNullAndNonNullInclusion() throws Exception {
206 assertEquals("Non-NULL inclusion means null members should not be in the output",
207 "{}", marshaller.marshal(new JsonBeanInclusionNonNull(null)));
208 }
209
210 @XmlRootElement
211 private static class ObjectWithMember {
212 @SuppressWarnings("unused")
213 @XmlElement
214 private final String string;
215
216 public ObjectWithMember(String string) {
217 this.string = string;
218 }
219 }
220
221 @XmlRootElement
222 private static class ObjectWithMemberMissingAnnotation {
223 @SuppressWarnings("unused")
224 private final String string;
225
226 public ObjectWithMemberMissingAnnotation(String string) {
227 this.string = string;
228 }
229 }
230
231 @XmlRootElement
232 private static class ObjectWithMemberWithRenaming {
233 @SuppressWarnings("unused")
234 @XmlElement(name = "str")
235 private final String string;
236
237 public ObjectWithMemberWithRenaming(String string) {
238 this.string = string;
239 }
240 }
241
242 static class JsonBeanInclusionDefault {
243 @JsonProperty
244 public final String name;
245
246 JsonBeanInclusionDefault(String name) {
247 this.name = name;
248 }
249 }
250
251 @JsonSerialize
252 static class JsonBeanWithAnnotationButNoExplicitInclusion {
253 @JsonProperty
254 public final String name;
255
256 JsonBeanWithAnnotationButNoExplicitInclusion(String name) {
257 this.name = name;
258 }
259 }
260
261 @JsonSerialize(include = Inclusion.ALWAYS)
262 static class JsonBeanInclusionAlways {
263 @JsonProperty
264 public final String name;
265
266 JsonBeanInclusionAlways(String name) {
267 this.name = name;
268 }
269 }
270
271 @JsonSerialize(include = Inclusion.NON_NULL)
272 static class JsonBeanInclusionNonNull {
273 @JsonProperty
274 public final String name;
275
276 JsonBeanInclusionNonNull(String name) {
277 this.name = name;
278 }
279 }
280 }
281