1 package com.fasterxml.jackson.databind.struct; 2 3 import com.fasterxml.jackson.annotation.JsonUnwrapped; 4 import com.fasterxml.jackson.databind.BaseMapTest; 5 import com.fasterxml.jackson.databind.MapperFeature; 6 import com.fasterxml.jackson.databind.ObjectMapper; 7 import com.fasterxml.jackson.databind.json.JsonMapper; 8 9 public class TestUnwrappedWithPrefix extends BaseMapTest 10 { 11 static class Unwrapping { 12 public String name; 13 @JsonUnwrapped 14 public Location location; 15 Unwrapping()16 public Unwrapping() { } Unwrapping(String str, int x, int y)17 public Unwrapping(String str, int x, int y) { 18 name = str; 19 location = new Location(x, y); 20 } 21 } 22 23 static class DeepUnwrapping 24 { 25 @JsonUnwrapped 26 public Unwrapping unwrapped; 27 DeepUnwrapping()28 public DeepUnwrapping() { } DeepUnwrapping(String str, int x, int y)29 public DeepUnwrapping(String str, int x, int y) { 30 unwrapped = new Unwrapping(str, x, y); 31 } 32 } 33 34 static class Location { 35 public int x; 36 public int y; 37 Location()38 public Location() { } Location(int x, int y)39 public Location(int x, int y) { 40 this.x = x; 41 this.y = y; 42 } 43 } 44 45 // Class with unwrapping using prefixes 46 static class PrefixUnwrap 47 { 48 public String name; 49 @JsonUnwrapped(prefix="_") 50 public Location location; 51 PrefixUnwrap()52 public PrefixUnwrap() { } PrefixUnwrap(String str, int x, int y)53 public PrefixUnwrap(String str, int x, int y) { 54 name = str; 55 location = new Location(x, y); 56 } 57 } 58 59 static class DeepPrefixUnwrap 60 { 61 @JsonUnwrapped(prefix="u.") 62 public PrefixUnwrap unwrapped; 63 DeepPrefixUnwrap()64 public DeepPrefixUnwrap() { } DeepPrefixUnwrap(String str, int x, int y)65 public DeepPrefixUnwrap(String str, int x, int y) { 66 unwrapped = new PrefixUnwrap(str, x, y); 67 } 68 } 69 70 // Let's actually test hierarchic names with unwrapping bit more: 71 72 static class ConfigRoot 73 { 74 @JsonUnwrapped(prefix="general.") 75 public ConfigGeneral general = new ConfigGeneral(); 76 77 @JsonUnwrapped(prefix="misc.") 78 public ConfigMisc misc = new ConfigMisc(); 79 ConfigRoot()80 public ConfigRoot() { } ConfigRoot(String name, int value)81 public ConfigRoot(String name, int value) 82 { 83 general = new ConfigGeneral(name); 84 misc.value = value; 85 } 86 } 87 88 static class ConfigAlternate 89 { 90 @JsonUnwrapped 91 public ConfigGeneral general = new ConfigGeneral(); 92 93 @JsonUnwrapped(prefix="misc.") 94 public ConfigMisc misc = new ConfigMisc(); 95 96 public int id; 97 ConfigAlternate()98 public ConfigAlternate() { } ConfigAlternate(int id, String name, int value)99 public ConfigAlternate(int id, String name, int value) 100 { 101 this.id = id; 102 general = new ConfigGeneral(name); 103 misc.value = value; 104 } 105 } 106 107 static class ConfigGeneral 108 { 109 @JsonUnwrapped(prefix="names.") 110 public ConfigNames names = new ConfigNames(); 111 ConfigGeneral()112 public ConfigGeneral() { } ConfigGeneral(String name)113 public ConfigGeneral(String name) { 114 names.name = name; 115 } 116 } 117 118 static class ConfigNames { 119 public String name = "x"; 120 } 121 122 static class ConfigMisc { 123 public int value; 124 } 125 126 // For [Issue#226] 127 static class Parent { 128 @JsonUnwrapped(prefix="c1.") 129 public Child c1; 130 @JsonUnwrapped(prefix="c2.") 131 public Child c2; 132 } 133 134 static class Child { 135 @JsonUnwrapped(prefix="sc2.") 136 public SubChild sc1; 137 } 138 139 static class SubChild { 140 public String value; 141 } 142 143 /* 144 /********************************************************** 145 /* Tests, serialization 146 /********************************************************** 147 */ 148 149 private final ObjectMapper MAPPER = new ObjectMapper(); 150 testPrefixedUnwrappingSerialize()151 public void testPrefixedUnwrappingSerialize() throws Exception 152 { 153 JsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build(); 154 assertEquals("{\"_x\":1,\"_y\":2,\"name\":\"Tatu\"}", 155 mapper.writeValueAsString(new PrefixUnwrap("Tatu", 1, 2))); 156 } 157 testDeepPrefixedUnwrappingSerialize()158 public void testDeepPrefixedUnwrappingSerialize() throws Exception 159 { 160 JsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build(); 161 String json = mapper.writeValueAsString(new DeepPrefixUnwrap("Bubba", 1, 1)); 162 assertEquals("{\"u._x\":1,\"u._y\":1,\"u.name\":\"Bubba\"}", json); 163 } 164 testHierarchicConfigSerialize()165 public void testHierarchicConfigSerialize() throws Exception 166 { 167 String json = MAPPER.writeValueAsString(new ConfigRoot("Fred", 25)); 168 assertEquals("{\"general.names.name\":\"Fred\",\"misc.value\":25}", json); 169 } 170 171 /* 172 /********************************************************** 173 /* Tests, deserialization 174 /********************************************************** 175 */ 176 testPrefixedUnwrapping()177 public void testPrefixedUnwrapping() throws Exception 178 { 179 PrefixUnwrap bean = MAPPER.readValue("{\"name\":\"Axel\",\"_x\":4,\"_y\":7}", PrefixUnwrap.class); 180 assertNotNull(bean); 181 assertEquals("Axel", bean.name); 182 assertNotNull(bean.location); 183 assertEquals(4, bean.location.x); 184 assertEquals(7, bean.location.y); 185 } 186 testDeepPrefixedUnwrappingDeserialize()187 public void testDeepPrefixedUnwrappingDeserialize() throws Exception 188 { 189 DeepPrefixUnwrap bean = MAPPER.readValue("{\"u.name\":\"Bubba\",\"u._x\":2,\"u._y\":3}", 190 DeepPrefixUnwrap.class); 191 assertNotNull(bean.unwrapped); 192 assertNotNull(bean.unwrapped.location); 193 assertEquals(2, bean.unwrapped.location.x); 194 assertEquals(3, bean.unwrapped.location.y); 195 assertEquals("Bubba", bean.unwrapped.name); 196 } 197 testHierarchicConfigDeserialize()198 public void testHierarchicConfigDeserialize() throws Exception 199 { 200 ConfigRoot root = MAPPER.readValue("{\"general.names.name\":\"Bob\",\"misc.value\":3}", 201 ConfigRoot.class); 202 assertNotNull(root.general); 203 assertNotNull(root.general.names); 204 assertNotNull(root.misc); 205 assertEquals(3, root.misc.value); 206 assertEquals("Bob", root.general.names.name); 207 } 208 209 /* 210 /********************************************************** 211 /* Tests, round-trip 212 /********************************************************** 213 */ 214 testHierarchicConfigRoundTrip()215 public void testHierarchicConfigRoundTrip() throws Exception 216 { 217 ConfigAlternate input = new ConfigAlternate(123, "Joe", 42); 218 String json = MAPPER.writeValueAsString(input); 219 220 ConfigAlternate root = MAPPER.readValue(json, ConfigAlternate.class); 221 assertEquals(123, root.id); 222 assertNotNull(root.general); 223 assertNotNull(root.general.names); 224 assertNotNull(root.misc); 225 assertEquals("Joe", root.general.names.name); 226 assertEquals(42, root.misc.value); 227 } 228 testIssue226()229 public void testIssue226() throws Exception 230 { 231 Parent input = new Parent(); 232 input.c1 = new Child(); 233 input.c1.sc1 = new SubChild(); 234 input.c1.sc1.value = "a"; 235 input.c2 = new Child(); 236 input.c2.sc1 = new SubChild(); 237 input.c2.sc1.value = "b"; 238 239 String json = MAPPER.writeValueAsString(input); 240 241 Parent output = MAPPER.readValue(json, Parent.class); 242 assertNotNull(output.c1); 243 assertNotNull(output.c2); 244 245 assertNotNull(output.c1.sc1); 246 assertNotNull(output.c2.sc1); 247 248 assertEquals("a", output.c1.sc1.value); 249 assertEquals("b", output.c2.sc1.value); 250 } 251 } 252