1 package com.fasterxml.jackson.databind.struct;
2 
3 import com.fasterxml.jackson.annotation.*;
4 
5 import com.fasterxml.jackson.databind.*;
6 import com.fasterxml.jackson.databind.json.JsonMapper;
7 
8 /**
9  * Unit tests for verifying that basic {@link JsonUnwrapped} annotation
10  * handling works as expected; some more advanced tests are separated out
11  * to more specific test classes (like prefix/suffix handling).
12  */
13 public class TestUnwrapped extends BaseMapTest
14 {
15     static class Unwrapping {
16         public String name;
17         @JsonUnwrapped
18         public Location location;
19 
Unwrapping()20         public Unwrapping() { }
Unwrapping(String str, int x, int y)21         public Unwrapping(String str, int x, int y) {
22             name = str;
23             location = new Location(x, y);
24         }
25     }
26 
27     final static class Location {
28         public int x;
29         public int y;
30 
Location()31         public Location() { }
Location(int x, int y)32         public Location(int x, int y) {
33             this.x = x;
34             this.y = y;
35         }
36     }
37 
38     static class DeepUnwrapping
39     {
40         @JsonUnwrapped
41         public Unwrapping unwrapped;
42 
DeepUnwrapping()43         public DeepUnwrapping() { }
DeepUnwrapping(String str, int x, int y)44         public DeepUnwrapping(String str, int x, int y) {
45             unwrapped = new Unwrapping(str, x, y);
46         }
47     }
48 
49     static class UnwrappingWithCreator {
50         public String name;
51 
52         @JsonUnwrapped
53         public Location location;
54 
55         @JsonCreator
UnwrappingWithCreator(@sonProperty"name") String n)56         public UnwrappingWithCreator(@JsonProperty("name") String n) {
57             name = n;
58         }
59     }
60 
61     // Class with two unwrapped properties
62     static class TwoUnwrappedProperties {
63         @JsonUnwrapped
64         public Location location;
65         @JsonUnwrapped
66         public Name name;
67 
TwoUnwrappedProperties()68         public TwoUnwrappedProperties() { }
69     }
70 
71     static class Name {
72         public String first, last;
73     }
74 
75     // [databind#615]
76     static class Parent {
77         @JsonUnwrapped
78         public Child c1;
79 
Parent()80         public Parent() { }
Parent(String str)81         public Parent(String str) { c1 = new Child(str); }
82     }
83 
84     static class Child {
85         public String field;
86 
Child()87         public Child() { }
Child(String f)88         public Child(String f) { field = f; }
89     }
90 
91     static class Inner {
92         public String animal;
93     }
94 
95     static class Outer {
96         // @JsonProperty
97         @JsonUnwrapped
98         private Inner inner;
99     }
100 
101     // [databind#1493]: case-insensitive handling
102     static class Person {
103         @JsonUnwrapped(prefix = "businessAddress.")
104         public Address businessAddress;
105     }
106 
107     static class Address {
108         public String street;
109         public String addon;
110         public String zip;
111         public String town;
112         public String country;
113     }
114 
115     // [databind#2088]
116     static class Issue2088Bean {
117         int x;
118         int y;
119 
120         @JsonUnwrapped
121         Issue2088UnwrappedBean w;
122 
Issue2088Bean(@sonProperty"x") int x, @JsonProperty("y") int y)123         public Issue2088Bean(@JsonProperty("x") int x, @JsonProperty("y") int y) {
124             this.x = x;
125             this.y = y;
126         }
127 
setW(Issue2088UnwrappedBean w)128         public void setW(Issue2088UnwrappedBean w) {
129             this.w = w;
130         }
131     }
132 
133     static class Issue2088UnwrappedBean {
134         int a;
135         int b;
136 
Issue2088UnwrappedBean(@sonProperty"a") int a, @JsonProperty("b") int b)137         public Issue2088UnwrappedBean(@JsonProperty("a") int a, @JsonProperty("b") int b) {
138             this.a = a;
139             this.b = b;
140         }
141     }
142 
143     /*
144     /**********************************************************
145     /* Tests, serialization
146     /**********************************************************
147      */
148 
149     private final ObjectMapper MAPPER = new ObjectMapper();
150 
testSimpleUnwrappingSerialize()151     public void testSimpleUnwrappingSerialize() throws Exception {
152         JsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();
153         assertEquals("{\"x\":1,\"y\":2,\"name\":\"Tatu\"}",
154                 mapper.writeValueAsString(new Unwrapping("Tatu", 1, 2)));
155     }
156 
testDeepUnwrappingSerialize()157     public void testDeepUnwrappingSerialize() throws Exception {
158         JsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();
159         assertEquals("{\"x\":1,\"y\":2,\"name\":\"Tatu\"}",
160                 mapper.writeValueAsString(new DeepUnwrapping("Tatu", 1, 2)));
161     }
162 
163     /*
164     /**********************************************************
165     /* Tests, deserialization
166     /**********************************************************
167      */
168 
testSimpleUnwrappedDeserialize()169     public void testSimpleUnwrappedDeserialize() throws Exception
170     {
171         Unwrapping bean = MAPPER.readValue("{\"name\":\"Tatu\",\"y\":7,\"x\":-13}",
172                 Unwrapping.class);
173         assertEquals("Tatu", bean.name);
174         Location loc = bean.location;
175         assertNotNull(loc);
176         assertEquals(-13, loc.x);
177         assertEquals(7, loc.y);
178     }
179 
testDoubleUnwrapping()180     public void testDoubleUnwrapping() throws Exception
181     {
182         TwoUnwrappedProperties bean = MAPPER.readValue("{\"first\":\"Joe\",\"y\":7,\"last\":\"Smith\",\"x\":-13}",
183                 TwoUnwrappedProperties.class);
184         Location loc = bean.location;
185         assertNotNull(loc);
186         assertEquals(-13, loc.x);
187         assertEquals(7, loc.y);
188         Name name = bean.name;
189         assertNotNull(name);
190         assertEquals("Joe", name.first);
191         assertEquals("Smith", name.last);
192     }
193 
testDeepUnwrapping()194     public void testDeepUnwrapping() throws Exception
195     {
196         DeepUnwrapping bean = MAPPER.readValue("{\"x\":3,\"name\":\"Bob\",\"y\":27}",
197                 DeepUnwrapping.class);
198         Unwrapping uw = bean.unwrapped;
199         assertNotNull(uw);
200         assertEquals("Bob", uw.name);
201         Location loc = uw.location;
202         assertNotNull(loc);
203         assertEquals(3, loc.x);
204         assertEquals(27, loc.y);
205     }
206 
testUnwrappedDeserializeWithCreator()207     public void testUnwrappedDeserializeWithCreator() throws Exception
208     {
209         UnwrappingWithCreator bean = MAPPER.readValue("{\"x\":1,\"y\":2,\"name\":\"Tatu\"}",
210                 UnwrappingWithCreator.class);
211         assertEquals("Tatu", bean.name);
212         Location loc = bean.location;
213         assertNotNull(loc);
214         assertEquals(1, loc.x);
215         assertEquals(2, loc.y);
216     }
217 
testIssue615()218     public void testIssue615() throws Exception
219     {
220         Parent input = new Parent("name");
221         String json = MAPPER.writeValueAsString(input);
222         Parent output = MAPPER.readValue(json, Parent.class);
223         assertEquals("name", output.c1.field);
224     }
225 
testUnwrappedAsPropertyIndicator()226     public void testUnwrappedAsPropertyIndicator() throws Exception
227     {
228         Inner inner = new Inner();
229         inner.animal = "Zebra";
230 
231         Outer outer = new Outer();
232         outer.inner = inner;
233 
234         String actual = MAPPER.writeValueAsString(outer);
235 
236         assertTrue(actual.contains("animal"));
237         assertTrue(actual.contains("Zebra"));
238         assertFalse(actual.contains("inner"));
239     }
240 
241     // [databind#1493]: case-insensitive handling
testCaseInsensitiveUnwrap()242     public void testCaseInsensitiveUnwrap() throws Exception
243     {
244         ObjectMapper mapper = jsonMapperBuilder()
245                 .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
246                 .build();
247         Person p = mapper.readValue("{ }", Person.class);
248         assertNotNull(p);
249     }
250 
251     // [databind#2088]: accidental skipping of values
testIssue2088UnwrappedFieldsAfterLastCreatorProp()252     public void testIssue2088UnwrappedFieldsAfterLastCreatorProp() throws Exception
253     {
254         Issue2088Bean bean = MAPPER.readValue("{\"x\":1,\"a\":2,\"y\":3,\"b\":4}", Issue2088Bean.class);
255         assertEquals(1, bean.x);
256         assertEquals(2, bean.w.a);
257         assertEquals(3, bean.y);
258         assertEquals(4, bean.w.b);
259     }
260 }
261