1 package com.fasterxml.jackson.databind.deser; 2 3 import java.io.IOException; 4 5 import com.fasterxml.jackson.core.JsonParser; 6 import com.fasterxml.jackson.core.JsonProcessingException; 7 import com.fasterxml.jackson.databind.*; 8 import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 9 10 /** 11 * Testing for NPE due to race condition. 12 */ 13 public class TestConcurrency extends BaseMapTest 14 { 15 /* 16 /********************************************** 17 /* Helper beans 18 /********************************************** 19 */ 20 21 @JsonDeserialize(using=CustomBeanDeserializer.class) 22 static class Bean 23 { 24 public int value = 42; 25 } 26 27 /* 28 /********************************************** 29 /* Helper classes 30 /********************************************** 31 */ 32 33 /** 34 * Dummy deserializer used for verifying that partially handled (i.e. not yet 35 * resolved) deserializers are not allowed to be used. 36 */ 37 static class CustomBeanDeserializer 38 extends JsonDeserializer<Bean> 39 implements ResolvableDeserializer 40 { 41 protected volatile boolean resolved = false; 42 43 @Override deserialize(JsonParser jp, DeserializationContext ctxt)44 public Bean deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException 45 { 46 if (!resolved) { 47 throw new IOException("Deserializer not yet completely resolved"); 48 } 49 Bean b = new Bean(); 50 b.value = 13; 51 return b; 52 } 53 54 @Override resolve(DeserializationContext ctxt)55 public void resolve(DeserializationContext ctxt) throws JsonMappingException 56 { 57 try { 58 Thread.sleep(100L); 59 } catch (Exception e) { } 60 resolved = true; 61 } 62 } 63 64 /* 65 /********************************************** 66 /* Unit tests 67 /********************************************** 68 */ 69 testDeserializerResolution()70 public void testDeserializerResolution() throws Exception 71 { 72 /* Let's repeat couple of times, just to be sure; thread timing is not 73 * exact science; plus caching plays a role too 74 */ 75 final String JSON = "{\"value\":42}"; 76 77 for (int i = 0; i < 5; ++i) { 78 final ObjectMapper mapper = new ObjectMapper(); 79 Runnable r = new Runnable() { 80 @Override 81 public void run() { 82 try { 83 /*Bean b =*/ mapper.readValue(JSON, Bean.class); 84 } catch (Exception e) { } 85 } 86 }; 87 Thread t = new Thread(r); 88 t.start(); 89 // then let it proceed 90 Thread.sleep(10L); 91 // and try the same... 92 Bean b = mapper.readValue(JSON, Bean.class); 93 // note: funny deserializer, mangles data.. :) 94 assertEquals(13, b.value); 95 t.join(); 96 } 97 } 98 } 99