1 package com.fasterxml.jackson.databind.convert; 2 3 import java.io.IOException; 4 import java.util.*; 5 6 import com.fasterxml.jackson.annotation.*; 7 import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; 8 import com.fasterxml.jackson.core.*; 9 import com.fasterxml.jackson.databind.*; 10 import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 11 import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 12 import com.fasterxml.jackson.databind.module.SimpleModule; 13 14 import static org.junit.Assert.assertArrayEquals; 15 16 /** 17 * Unit tests for verifying that "updating reader" works as 18 * expected. 19 */ 20 @SuppressWarnings("serial") 21 public class TestUpdateViaObjectReader extends BaseMapTest 22 { 23 static class Bean { 24 public String a = "a"; 25 public String b = "b"; 26 27 public int[] c = new int[] { 1, 2, 3 }; 28 29 public Bean child = null; 30 } 31 32 static class XYBean { 33 public int x, y; 34 } 35 36 public class TextView {} 37 public class NumView {} 38 39 public class Updateable { 40 @JsonView(NumView.class) 41 public int num; 42 43 @JsonView(TextView.class) 44 public String str; 45 } 46 47 // for [databind#744] 48 static class DataA { 49 public int i = 1; 50 public int j = 2; 51 52 } 53 54 static class DataB { 55 public DataA da = new DataA(); 56 public int k = 3; 57 } 58 59 static class DataADeserializer extends StdDeserializer<DataA> { 60 private static final long serialVersionUID = 1L; 61 DataADeserializer()62 DataADeserializer() { 63 super(DataA.class); 64 } 65 66 @Override deserialize(JsonParser p, DeserializationContext ctxt)67 public DataA deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { 68 if (p.currentToken() != JsonToken.START_OBJECT) { 69 ctxt.reportInputMismatch(DataA.class, 70 "Wrong current token, expected START_OBJECT, got: " 71 +p.currentToken()); 72 // never gets here 73 } 74 /*JsonNode node =*/ p.readValueAsTree(); 75 76 DataA da = new DataA(); 77 da.i = 5; 78 return da; 79 } 80 } 81 82 // [databind#1831] 83 @JsonTypeInfo(use = Id.NAME) 84 @JsonSubTypes({ @JsonSubTypes.Type(value = Cat.class) }) 85 static abstract public class AbstractAnimal { } 86 87 @JsonDeserialize(using = AnimalWrapperDeserializer.class) 88 static class AnimalWrapper { 89 @JsonUnwrapped 90 protected AbstractAnimal animal; 91 setAnimal(AbstractAnimal animal)92 public void setAnimal(AbstractAnimal animal) { 93 this.animal = animal; 94 } 95 } 96 97 static class Cat extends AbstractAnimal { } 98 99 static class AnimalWrapperDeserializer extends StdDeserializer<AnimalWrapper> { AnimalWrapperDeserializer()100 public AnimalWrapperDeserializer() { 101 super(AnimalWrapper.class); 102 } 103 104 @Override deserialize(JsonParser json, DeserializationContext context)105 public AnimalWrapper deserialize(JsonParser json, DeserializationContext context) throws IOException { 106 AnimalWrapper msg = new AnimalWrapper(); 107 msg.setAnimal(json.readValueAs(AbstractAnimal.class)); 108 return msg; 109 } 110 111 @Override deserialize(JsonParser json, DeserializationContext context, AnimalWrapper intoValue)112 public AnimalWrapper deserialize(JsonParser json, DeserializationContext context, AnimalWrapper intoValue) throws IOException { 113 intoValue.setAnimal(json.readValueAs(AbstractAnimal.class)); 114 return intoValue; 115 } 116 } 117 118 /* 119 /******************************************************** 120 /* Test methods 121 /******************************************************** 122 */ 123 124 private final ObjectMapper MAPPER = new ObjectMapper(); 125 testBeanUpdate()126 public void testBeanUpdate() throws Exception 127 { 128 Bean bean = new Bean(); 129 assertEquals("b", bean.b); 130 assertEquals(3, bean.c.length); 131 assertNull(bean.child); 132 133 Object ob = MAPPER.readerForUpdating(bean).readValue("{ \"b\":\"x\", \"c\":[4,5], \"child\":{ \"a\":\"y\"} }"); 134 assertSame(ob, bean); 135 136 assertEquals("a", bean.a); 137 assertEquals("x", bean.b); 138 assertArrayEquals(new int[] { 4, 5 }, bean.c); 139 140 Bean child = bean.child; 141 assertNotNull(child); 142 assertEquals("y", child.a); 143 assertEquals("b", child.b); 144 assertArrayEquals(new int[] { 1, 2, 3 }, child.c); 145 assertNull(child.child); 146 } 147 testListUpdate()148 public void testListUpdate() throws Exception 149 { 150 List<String> strs = new ArrayList<String>(); 151 strs.add("a"); 152 // for lists, we will be appending entries 153 Object ob = MAPPER.readerForUpdating(strs).readValue("[ \"b\", \"c\", \"d\" ]"); 154 assertSame(strs, ob); 155 assertEquals(4, strs.size()); 156 assertEquals("a", strs.get(0)); 157 assertEquals("b", strs.get(1)); 158 assertEquals("c", strs.get(2)); 159 assertEquals("d", strs.get(3)); 160 } 161 testMapUpdate()162 public void testMapUpdate() throws Exception 163 { 164 Map<String,String> strs = new HashMap<String,String>(); 165 strs.put("a", "a"); 166 strs.put("b", "b"); 167 // for maps, we will be adding and/or overwriting entries 168 Object ob = MAPPER.readerForUpdating(strs).readValue("{ \"c\" : \"c\", \"a\" : \"z\" }"); 169 assertSame(strs, ob); 170 assertEquals(3, strs.size()); 171 assertEquals("z", strs.get("a")); 172 assertEquals("b", strs.get("b")); 173 assertEquals("c", strs.get("c")); 174 } 175 176 // Test for [JACKSON-717] -- ensure 'readValues' also does update 177 @SuppressWarnings("resource") testUpdateSequence()178 public void testUpdateSequence() throws Exception 179 { 180 XYBean toUpdate = new XYBean(); 181 Iterator<XYBean> it = MAPPER.readerForUpdating(toUpdate).readValues( 182 "{\"x\":1,\"y\":2}\n{\"x\":16}{\"y\":37}"); 183 184 assertTrue(it.hasNext()); 185 XYBean value = it.next(); 186 assertSame(toUpdate, value); 187 assertEquals(1, value.x); 188 assertEquals(2, value.y); 189 190 assertTrue(it.hasNext()); 191 value = it.next(); 192 assertSame(toUpdate, value); 193 assertEquals(16, value.x); 194 assertEquals(2, value.y); // unchanged 195 196 assertTrue(it.hasNext()); 197 value = it.next(); 198 assertSame(toUpdate, value); 199 assertEquals(16, value.x); // unchanged 200 assertEquals(37, value.y); 201 202 assertFalse(it.hasNext()); 203 } 204 205 // [JACKSON-824] testUpdatingWithViews()206 public void testUpdatingWithViews() throws Exception 207 { 208 Updateable bean = new Updateable(); 209 bean.num = 100; 210 bean.str = "test"; 211 Updateable result = MAPPER.readerForUpdating(bean) 212 .withView(TextView.class) 213 .readValue("{\"num\": 10, \"str\":\"foobar\"}"); 214 assertSame(bean, result); 215 216 assertEquals(100, bean.num); 217 assertEquals("foobar", bean.str); 218 } 219 220 // [databind#744] testIssue744()221 public void testIssue744() throws IOException 222 { 223 ObjectMapper mapper = new ObjectMapper(); 224 SimpleModule module = new SimpleModule(); 225 module.addDeserializer(DataA.class, new DataADeserializer()); 226 mapper.registerModule(module); 227 228 DataB db = new DataB(); 229 db.da.i = 11; 230 db.k = 13; 231 String jsonBString = mapper.writeValueAsString(db); 232 JsonNode jsonBNode = mapper.valueToTree(db); 233 234 // create parent 235 DataB dbNewViaString = mapper.readValue(jsonBString, DataB.class); 236 assertEquals(5, dbNewViaString.da.i); 237 assertEquals(13, dbNewViaString.k); 238 239 DataB dbNewViaNode = mapper.treeToValue(jsonBNode, DataB.class); 240 assertEquals(5, dbNewViaNode.da.i); 241 assertEquals(13, dbNewViaNode.k); 242 243 // update parent 244 DataB dbUpdViaString = new DataB(); 245 DataB dbUpdViaNode = new DataB(); 246 247 assertEquals(1, dbUpdViaString.da.i); 248 assertEquals(3, dbUpdViaString.k); 249 mapper.readerForUpdating(dbUpdViaString).readValue(jsonBString); 250 assertEquals(5, dbUpdViaString.da.i); 251 assertEquals(13, dbUpdViaString.k); 252 253 assertEquals(1, dbUpdViaNode.da.i); 254 assertEquals(3, dbUpdViaNode.k); 255 256 mapper.readerForUpdating(dbUpdViaNode).readValue(jsonBNode); 257 assertEquals(5, dbUpdViaNode.da.i); 258 assertEquals(13, dbUpdViaNode.k); 259 } 260 261 // [databind#1831] test1831UsingNode()262 public void test1831UsingNode() throws IOException { 263 String catJson = MAPPER.writeValueAsString(new Cat()); 264 JsonNode jsonNode = MAPPER.readTree(catJson); 265 AnimalWrapper optionalCat = new AnimalWrapper(); 266 ObjectReader r = MAPPER.readerForUpdating(optionalCat); 267 AnimalWrapper result = r.readValue(jsonNode); 268 assertSame(optionalCat, result); 269 } 270 test1831UsingString()271 public void test1831UsingString() throws IOException { 272 String catJson = MAPPER.writeValueAsString(new Cat()); 273 AnimalWrapper optionalCat = new AnimalWrapper(); 274 AnimalWrapper result = MAPPER.readerForUpdating(optionalCat).readValue(catJson); 275 assertSame(optionalCat, result); 276 } 277 } 278