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