• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind.misc;
2 
3 import java.util.*;
4 import java.util.concurrent.*;
5 
6 import com.fasterxml.jackson.annotation.*;
7 
8 import com.fasterxml.jackson.databind.BaseMapTest;
9 import com.fasterxml.jackson.databind.JsonNode;
10 import com.fasterxml.jackson.databind.ObjectMapper;
11 
12 public class RaceCondition738Test extends BaseMapTest
13 {
14     static abstract class AbstractHasSubTypes implements HasSubTypes { }
15 
16     static class TypeOne extends AbstractHasSubTypes {
17         private final String id;
TypeOne(String id)18         public TypeOne(String id) {
19             this.id = id;
20         }
21         @JsonProperty
getId()22         public String getId() {
23             return id;
24         }
25         @Override
getType()26         public String getType() {
27             return TypeOne.class.getSimpleName();
28         }
29     }
30 
31     @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
32     @JsonSubTypes({
33         @JsonSubTypes.Type(value = TypeOne.class, name = "one")
34     })
35     public interface HasSubTypes {
getType()36         String getType();
37     }
38 
39     static class Wrapper {
40         private final HasSubTypes hasSubTypes;
41 
Wrapper(HasSubTypes hasSubTypes)42         private Wrapper(HasSubTypes hasSubTypes) {
43             this.hasSubTypes = hasSubTypes;
44         }
45 
46         @JsonProperty
getHasSubTypes()47         public HasSubTypes getHasSubTypes() {
48             return hasSubTypes;
49         }
50     }
51 
52     /*
53     /**********************************************************
54     /* Test methods
55     /**********************************************************
56      */
57 
testRepeatedly()58     public void testRepeatedly() throws Exception {
59         final int COUNT = 3000;
60         for (int i = 0; i < COUNT; i++) {
61             runOnce(i, COUNT);
62         }
63     }
64 
runOnce(int round, int max)65     void runOnce(int round, int max) throws Exception {
66         final ObjectMapper mapper = newJsonMapper();
67         Callable<String> writeJson = new Callable<String>() {
68             @Override
69             public String call() throws Exception {
70                 Wrapper wrapper = new Wrapper(new TypeOne("test"));
71                 return mapper.writeValueAsString(wrapper);
72             }
73         };
74 
75         int numThreads = 4;
76         ExecutorService executor = Executors.newFixedThreadPool(numThreads);
77         List<Future<String>> jsonFutures = new ArrayList<Future<String>>();
78         for (int i = 0; i < numThreads; i++) {
79             jsonFutures.add(executor.submit(writeJson));
80         }
81 
82         executor.shutdown();
83         executor.awaitTermination(5, TimeUnit.SECONDS);
84 
85         for (Future<String> jsonFuture : jsonFutures) {
86             String json = jsonFuture.get();
87             JsonNode tree = mapper.readTree(json);
88             JsonNode wrapped = tree.get("hasSubTypes");
89 
90             if (!wrapped.has("one")) {
91                 throw new IllegalStateException("Round #"+round+"/"+max+" ; missing property 'one', source: "+json);
92             }
93         }
94     }
95 }
96