• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind.misc;
2 
3 import java.util.List;
4 
5 import com.fasterxml.jackson.annotation.JsonCreator;
6 import com.fasterxml.jackson.annotation.JsonFormat;
7 import com.fasterxml.jackson.annotation.JsonProperty;
8 
9 import com.fasterxml.jackson.core.JsonProcessingException;
10 
11 import com.fasterxml.jackson.databind.*;
12 import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
13 
14 public class CaseInsensitiveDeserTest extends BaseMapTest
15 {
16     // [databind#1036]
17     static class BaseResponse {
18         public int errorCode;
19         public String debugMessage;
20     }
21 
22     static class Issue476Bean {
23         public Issue476Type value1, value2;
24     }
25     static class Issue476Type {
26         public String name, value;
27     }
28 
29     // [databind#1232]: allow per-property case-insensitivity
30     static class Role {
31         public String ID;
32         public String Name;
33     }
34 
35     static class CaseInsensitiveRoleWrapper
36     {
37         @JsonFormat(with={ JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES })
38         public Role role;
39     }
40 
41     // [databind#1438]
42     static class InsensitiveCreator
43     {
44         int v;
45 
46         @JsonCreator
InsensitiveCreator(@sonProperty"value") int v0)47         public InsensitiveCreator(@JsonProperty("value") int v0) {
48             v = v0;
49         }
50     }
51 
52     // [databind#1854]
53     static class Obj1854 {
54         private final int id;
55 
56         private final List<ChildObj1854> items;
57 
Obj1854(int id, List<ChildObj1854> items)58         public Obj1854(int id, List<ChildObj1854> items) {
59             this.id = id;
60             this.items = items;
61         }
62 
63         @JsonCreator
fromJson(@sonProperty"ID") int id, @JsonProperty("Items") List<ChildObj1854> items)64         public static Obj1854 fromJson(@JsonProperty("ID") int id,
65                 @JsonProperty("Items") List<ChildObj1854> items) {
66             return new Obj1854(id, items);
67         }
68 
getId()69         public int getId() {
70             return id;
71         }
72 
getItems()73         public List<ChildObj1854> getItems() {
74             return items;
75         }
76 
77     }
78 
79     // [databind#1854]
80     static class ChildObj1854 {
81         private final String childId;
82 
ChildObj1854(String id)83         private ChildObj1854(String id) {
84             this.childId = id;
85         }
86 
87         @JsonCreator
fromJson(@sonProperty"ChildID") String cid)88         public static ChildObj1854 fromJson(@JsonProperty("ChildID") String cid) {
89             return new ChildObj1854(cid);
90         }
91 
getId()92         public String getId() {
93             return childId;
94         }
95     }
96 
97     // [databind#1886]: allow case-insensitivity by default on a class
98     @JsonFormat(with={ JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES })
99     static class CaseInsensitiveRole {
100         public String ID;
101         public String Name;
102     }
103 
104     // [databind#1886]: allow case-insensitivity by default on a class
105     static class CaseInsensitiveRoleContainer {
106         public CaseInsensitiveRole role;
107     }
108 
109     // [databind#1886]: ... but also overrides
110     static class CaseSensitiveRoleContainer {
111         @JsonFormat(without={ JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES })
112         public CaseInsensitiveRole role;
113     }
114 
115     /*
116     /********************************************************
117     /* Test methods
118     /********************************************************
119      */
120 
121     private final ObjectMapper MAPPER = newJsonMapper();
122     private final ObjectMapper INSENSITIVE_MAPPER = jsonMapperBuilder()
123             .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
124             .build();
125 
126     // [databind#566]
testCaseInsensitiveDeserialization()127     public void testCaseInsensitiveDeserialization() throws Exception
128     {
129         final String JSON = "{\"Value1\" : {\"nAme\" : \"fruit\", \"vALUe\" : \"apple\"}, \"valUE2\" : {\"NAME\" : \"color\", \"value\" : \"red\"}}";
130 
131         // first, verify default settings which do not accept improper case
132         ObjectMapper mapper = new ObjectMapper();
133         assertFalse(mapper.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES));
134         try {
135             mapper.readValue(JSON, Issue476Bean.class);
136 
137             fail("Should not accept improper case properties by default");
138         } catch (JsonProcessingException e) {
139             verifyException(e, "Unrecognized field");
140             assertValidLocation(e.getLocation());
141         }
142 
143         // Definitely not OK to enable dynamically - the BeanPropertyMap (which is the consumer of this particular feature) gets cached.
144         ObjectReader r = INSENSITIVE_MAPPER.readerFor(Issue476Bean.class);
145         Issue476Bean result = r.readValue(JSON);
146         assertEquals(result.value1.name, "fruit");
147         assertEquals(result.value1.value, "apple");
148     }
149 
150     // [databind#1036]
testCaseInsensitive1036()151     public void testCaseInsensitive1036() throws Exception
152     {
153         final String json = "{\"ErrorCode\":2,\"DebugMessage\":\"Signature not valid!\"}";
154 //        final String json = "{\"errorCode\":2,\"debugMessage\":\"Signature not valid!\"}";
155 
156         BaseResponse response = INSENSITIVE_MAPPER.readValue(json, BaseResponse.class);
157         assertEquals(2, response.errorCode);
158         assertEquals("Signature not valid!", response.debugMessage);
159     }
160 
161     // [databind#1232]: allow per-property case-insensitivity
testCaseInsensitiveWithFormat()162     public void testCaseInsensitiveWithFormat() throws Exception {
163         CaseInsensitiveRoleWrapper w = MAPPER.readValue
164                 (aposToQuotes("{'role':{'id':'12','name':'Foo'}}"),
165                         CaseInsensitiveRoleWrapper.class);
166         assertNotNull(w);
167         assertEquals("12", w.role.ID);
168         assertEquals("Foo", w.role.Name);
169     }
170 
171     // [databind#1438]
testCreatorWithInsensitive()172     public void testCreatorWithInsensitive() throws Exception
173     {
174         final String json = aposToQuotes("{'VALUE':3}");
175         InsensitiveCreator bean = INSENSITIVE_MAPPER.readValue(json, InsensitiveCreator.class);
176         assertEquals(3, bean.v);
177     }
178 
179     // And allow config overrides too
testCaseInsensitiveViaConfigOverride()180     public void testCaseInsensitiveViaConfigOverride() throws Exception
181     {
182         ObjectMapper mapper = new ObjectMapper();
183         mapper.configOverride(Role.class)
184             .setFormat(JsonFormat.Value.empty()
185                     .withFeature(JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES));
186         Role role = mapper.readValue
187                 (aposToQuotes("{'id':'12','name':'Foo'}"),
188                         Role.class);
189         assertNotNull(role);
190         assertEquals("12", role.ID);
191         assertEquals("Foo", role.Name);
192     }
193 
testIssue1854()194     public void testIssue1854() throws Exception
195     {
196         final String DOC = aposToQuotes("{'ID': 1, 'Items': [ { 'ChildID': 10 } ]}");
197         Obj1854 result = INSENSITIVE_MAPPER.readValue(DOC, Obj1854.class);
198         assertNotNull(result);
199         assertEquals(1, result.getId());
200         assertNotNull(result.getItems());
201         assertEquals(1, result.getItems().size());
202     }
203 
204 
205     // [databind#1886]: allow case-insensitivity by default on a class
testCaseInsensitiveViaClassAnnotation()206     public void testCaseInsensitiveViaClassAnnotation() throws Exception
207     {
208         final String CONTAINED = aposToQuotes("{'role': {'id':'3','name':'Bob'}}");
209 
210         // First: via wrapper/container:
211         CaseInsensitiveRoleContainer cont = MAPPER.readValue(CONTAINED,
212                         CaseInsensitiveRoleContainer.class);
213         assertEquals("3", cont.role.ID);
214         assertEquals("Bob", cont.role.Name);
215 
216         // second: directly as root value
217         CaseInsensitiveRole role = MAPPER.readValue
218                 (aposToQuotes("{'id':'12','name':'Billy'}"),
219                         CaseInsensitiveRole.class);
220         assertEquals("12", role.ID);
221         assertEquals("Billy", role.Name);
222 
223         // and finally, more complicated; should be possible to force sensitivity:
224         try {
225             /*CaseSensitiveRoleContainer r =*/ MAPPER.readValue(CONTAINED,
226                     CaseSensitiveRoleContainer.class);
227             fail("Should not pass");
228         } catch (UnrecognizedPropertyException e) {
229             verifyException(e, "Unrecognized ");
230             verifyException(e, "\"id\"");
231         }
232     }
233 }
234