• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind;
2 
3 import com.fasterxml.jackson.annotation.*;
4 
5 import com.fasterxml.jackson.databind.ObjectMapper;
6 import com.fasterxml.jackson.databind.exc.MismatchedInputException;
7 import com.fasterxml.jackson.databind.json.JsonMapper;
8 
9 /**
10  * Unit tests dealing with handling of "root element wrapping",
11  * including configuration of root name to use.
12  */
13 public class TestRootName extends BaseMapTest
14 {
15     @JsonRootName("rudy")
16     static class Bean {
17         public int a = 3;
18     }
19 
20     @JsonRootName("")
21     static class RootBeanWithEmpty {
22         public int a = 2;
23     }
24 
25     /*
26     /**********************************************************
27     /* Unit tests
28     /**********************************************************
29      */
30 
testRootViaMapper()31     public void testRootViaMapper() throws Exception
32     {
33         ObjectMapper mapper = rootMapper();
34         String json = mapper.writeValueAsString(new Bean());
35         assertEquals("{\"rudy\":{\"a\":3}}", json);
36         Bean bean = mapper.readValue(json, Bean.class);
37         assertNotNull(bean);
38 
39         // also same with explicitly "not defined"...
40         json = mapper.writeValueAsString(new RootBeanWithEmpty());
41         assertEquals("{\"RootBeanWithEmpty\":{\"a\":2}}", json);
42         RootBeanWithEmpty bean2 = mapper.readValue(json, RootBeanWithEmpty.class);
43         assertNotNull(bean2);
44         assertEquals(2, bean2.a);
45     }
46 
testRootViaMapperFails()47     public void testRootViaMapperFails() throws Exception
48     {
49         final ObjectMapper mapper = rootMapper();
50         // First kind of fail, wrong name
51         try {
52             mapper.readValue(aposToQuotes("{'notRudy':{'a':3}}"), Bean.class);
53             fail("Should not pass");
54         } catch (MismatchedInputException e) {
55             verifyException(e, "Root name 'notRudy' does not match expected ('rudy')");
56         }
57 
58         // second: non-Object
59         try {
60             mapper.readValue(aposToQuotes("[{'rudy':{'a':3}}]"), Bean.class);
61             fail("Should not pass");
62         } catch (MismatchedInputException e) {
63             verifyException(e, "Unexpected token (START_ARRAY");
64         }
65 
66         // Third: empty Object
67         try {
68             mapper.readValue(aposToQuotes("{}]"), Bean.class);
69             fail("Should not pass");
70         } catch (MismatchedInputException e) {
71             verifyException(e, "Current token not FIELD_NAME");
72         }
73 
74         // Fourth, stuff after wrapped
75         try {
76             mapper.readValue(aposToQuotes("{'rudy':{'a':3}, 'extra':3}"), Bean.class);
77             fail("Should not pass");
78         } catch (MismatchedInputException e) {
79             verifyException(e, "Unexpected token");
80             verifyException(e, "Current token not END_OBJECT (to match wrapper");
81         }
82     }
83 
testRootViaReaderFails()84     public void testRootViaReaderFails() throws Exception
85     {
86         final ObjectReader reader = rootMapper().readerFor(Bean.class);
87         // First kind of fail, wrong name
88         try {
89             reader.readValue(aposToQuotes("{'notRudy':{'a':3}}"));
90             fail("Should not pass");
91         } catch (MismatchedInputException e) {
92             verifyException(e, "Root name 'notRudy' does not match expected ('rudy')");
93         }
94 
95         // second: non-Object
96         try {
97             reader.readValue(aposToQuotes("[{'rudy':{'a':3}}]"));
98             fail("Should not pass");
99         } catch (MismatchedInputException e) {
100             verifyException(e, "Unexpected token (START_ARRAY");
101         }
102 
103         // Third: empty Object
104         try {
105             reader.readValue(aposToQuotes("{}]"));
106             fail("Should not pass");
107         } catch (MismatchedInputException e) {
108             verifyException(e, "Current token not FIELD_NAME");
109         }
110 
111         // Fourth, stuff after wrapped
112         try {
113             reader.readValue(aposToQuotes("{'rudy':{'a':3}, 'extra':3}"));
114             fail("Should not pass");
115         } catch (MismatchedInputException e) {
116             verifyException(e, "Unexpected token");
117             verifyException(e, "Current token not END_OBJECT (to match wrapper");
118         }
119     }
120 
testRootViaWriterAndReader()121     public void testRootViaWriterAndReader() throws Exception
122     {
123         ObjectMapper mapper = rootMapper();
124         String json = mapper.writer().writeValueAsString(new Bean());
125         assertEquals("{\"rudy\":{\"a\":3}}", json);
126         Bean bean = mapper.readerFor(Bean.class).readValue(json);
127         assertNotNull(bean);
128     }
129 
testReconfiguringOfWrapping()130     public void testReconfiguringOfWrapping() throws Exception
131     {
132         ObjectMapper mapper = new ObjectMapper();
133         // default: no wrapping
134         final Bean input = new Bean();
135         String jsonUnwrapped = mapper.writeValueAsString(input);
136         assertEquals("{\"a\":3}", jsonUnwrapped);
137         // secondary: wrapping
138         String jsonWrapped = mapper.writer(SerializationFeature.WRAP_ROOT_VALUE)
139             .writeValueAsString(input);
140         assertEquals("{\"rudy\":{\"a\":3}}", jsonWrapped);
141 
142         // and then similarly for readers:
143         Bean result = mapper.readValue(jsonUnwrapped, Bean.class);
144         assertNotNull(result);
145         try { // must not have extra wrapping
146             result = mapper.readerFor(Bean.class).with(DeserializationFeature.UNWRAP_ROOT_VALUE)
147                 .readValue(jsonUnwrapped);
148             fail("Should have failed");
149         } catch (JsonMappingException e) {
150             verifyException(e, "Root name 'a'");
151         }
152         // except wrapping may be expected:
153         result = mapper.readerFor(Bean.class).with(DeserializationFeature.UNWRAP_ROOT_VALUE)
154             .readValue(jsonWrapped);
155         assertNotNull(result);
156     }
157 
158     // [JACKSON-764]
testRootUsingExplicitConfig()159     public void testRootUsingExplicitConfig() throws Exception
160     {
161         ObjectMapper mapper = new ObjectMapper();
162         ObjectWriter writer = mapper.writer().withRootName("wrapper");
163         String json = writer.writeValueAsString(new Bean());
164         assertEquals("{\"wrapper\":{\"a\":3}}", json);
165 
166         ObjectReader reader = mapper.readerFor(Bean.class).withRootName("wrapper");
167         Bean bean = reader.readValue(json);
168         assertNotNull(bean);
169 
170         // also: verify that we can override SerializationFeature as well:
171         ObjectMapper wrapping = rootMapper();
172         json = wrapping.writer().withRootName("something").writeValueAsString(new Bean());
173         assertEquals("{\"something\":{\"a\":3}}", json);
174         json = wrapping.writer().withRootName("").writeValueAsString(new Bean());
175         assertEquals("{\"a\":3}", json);
176 
177         // 21-Apr-2015, tatu: Alternative available with 2.6 as well:
178         json = wrapping.writer().withoutRootName().writeValueAsString(new Bean());
179         assertEquals("{\"a\":3}", json);
180 
181         bean = wrapping.readerFor(Bean.class).withRootName("").readValue(json);
182         assertNotNull(bean);
183         assertEquals(3, bean.a);
184 
185         bean = wrapping.readerFor(Bean.class).withoutRootName().readValue("{\"a\":4}");
186         assertNotNull(bean);
187         assertEquals(4, bean.a);
188 
189         // and back to defaults
190         bean = wrapping.readerFor(Bean.class).readValue("{\"rudy\":{\"a\":7}}");
191         assertNotNull(bean);
192         assertEquals(7, bean.a);
193     }
194 
195     /*
196     /**********************************************************
197     /* Helper methods
198     /**********************************************************
199      */
200 
201     private final ObjectMapper ROOT_MAPPER = JsonMapper.builder()
202             .enable(SerializationFeature.WRAP_ROOT_VALUE)
203             .enable(DeserializationFeature.UNWRAP_ROOT_VALUE)
204             .build();
205 
rootMapper()206     private ObjectMapper rootMapper() {
207         return ROOT_MAPPER;
208     }
209 }
210