• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind.introspect;
2 
3 import java.util.Arrays;
4 import java.util.List;
5 
6 import com.fasterxml.jackson.annotation.*;
7 
8 import com.fasterxml.jackson.databind.*;
9 import com.fasterxml.jackson.databind.annotation.JsonNaming;
10 import com.fasterxml.jackson.databind.introspect.TestNamingStrategyCustom.PersonBean;
11 import com.fasterxml.jackson.databind.node.ObjectNode;
12 
13 /**
14  * Unit tests to verify functioning of standard {@link PropertyNamingStrategy}
15  * implementations Jackson includes out of the box.
16  */
17 public class TestNamingStrategyStd extends BaseMapTest
18 {
19     @JsonPropertyOrder({"www", "some_url", "some_uris"})
20     static class Acronyms
21     {
22         public String WWW;
23         public String someURL;
24         public String someURIs;
25 
Acronyms()26         public Acronyms() {this(null, null, null);}
Acronyms(String WWW, String someURL, String someURIs)27         public Acronyms(String WWW, String someURL, String someURIs)
28         {
29             this.WWW = WWW;
30             this.someURL = someURL;
31             this.someURIs = someURIs;
32         }
33     }
34 
35     @JsonPropertyOrder({"from_user", "user", "from$user", "from7user", "_x"})
36     static class UnchangedNames
37     {
38         public String from_user;
39         public String _user;
40         public String from$user;
41         public String from7user;
42         // Used to test "_", but it's explicitly deprecated in JDK8 so...
43         public String _x;
44 
UnchangedNames()45         public UnchangedNames() {this(null, null, null, null, null);}
UnchangedNames(String from_user, String _user, String from$user, String from7user, String _x)46         public UnchangedNames(String from_user, String _user, String from$user, String from7user, String _x)
47         {
48             this.from_user = from_user;
49             this._user = _user;
50             this.from$user = from$user;
51             this.from7user = from7user;
52             this._x = _x;
53         }
54     }
55 
56     @JsonPropertyOrder({"results", "user", "__", "$_user"})
57     static class OtherNonStandardNames
58     {
59         public String Results;
60         public String _User;
61         public String ___;
62         public String $User;
63 
OtherNonStandardNames()64         public OtherNonStandardNames() {this(null, null, null, null);}
OtherNonStandardNames(String Results, String _User, String ___, String $User)65         public OtherNonStandardNames(String Results, String _User, String ___, String $User)
66         {
67             this.Results = Results;
68             this._User = _User;
69             this.___ = ___;
70             this.$User = $User;
71         }
72     }
73 
74     static class Bean428 {
75         @JsonProperty("fooBar")
whatever()76         public String whatever() {return "";}
77     }
78 
79     @JsonPropertyOrder({ "firstName", "lastName" })
80     @JsonNaming(PropertyNamingStrategy.LowerCaseStrategy.class)
81     static class BoringBean {
82         public String firstName = "Bob";
83         public String lastName = "Burger";
84     }
85 
86     public static class ClassWithObjectNodeField {
87         public String id;
88         public ObjectNode json;
89     }
90 
91     static class ExplicitBean {
92         @JsonProperty("firstName")
93         String userFirstName = "Peter";
94         @JsonProperty("lastName")
95         String userLastName = "Venkman";
96         @JsonProperty
97         String userAge = "35";
98     }
99 
100     @JsonNaming()
101     static class DefaultNaming {
102         public int someValue = 3;
103     }
104 
105     static class FirstNameBean {
106         public String firstName;
107 
FirstNameBean()108         protected FirstNameBean() { }
FirstNameBean(String n)109         public FirstNameBean(String n) { firstName = n; }
110     }
111 
112     /*
113     /**********************************************************
114     /* Set up
115     /**********************************************************
116      */
117 
118     final static List<Object[]> SNAKE_CASE_NAME_TRANSLATIONS = Arrays.asList(new Object[][] {
119                 {null, null},
120                 {"", ""},
121                 {"a", "a"},
122                 {"abc", "abc"},
123                 {"1", "1"},
124                 {"123", "123"},
125                 {"1a", "1a"},
126                 {"a1", "a1"},
127                 {"$", "$"},
128                 {"$a", "$a"},
129                 {"a$", "a$"},
130                 {"$_a", "$_a"},
131                 {"a_$", "a_$"},
132                 {"a$a", "a$a"},
133                 {"$A", "$_a"},
134                 {"$_A", "$_a"},
135                 {"_", "_"},
136                 {"__", "_"},
137                 {"___", "__"},
138                 {"A", "a"},
139                 {"A1", "a1"},
140                 {"1A", "1_a"},
141                 {"_a", "a"},
142                 {"_A", "a"},
143                 {"a_a", "a_a"},
144                 {"a_A", "a_a"},
145                 {"A_A", "a_a"},
146                 {"A_a", "a_a"},
147                 {"WWW", "www"},
148                 {"someURI", "some_uri"},
149                 {"someURIs", "some_uris"},
150                 {"Results", "results"},
151                 {"_Results", "results"},
152                 {"_results", "results"},
153                 {"__results", "_results"},
154                 {"__Results", "_results"},
155                 {"___results", "__results"},
156                 {"___Results", "__results"},
157                 {"userName", "user_name"},
158                 {"user_name", "user_name"},
159                 {"user__name", "user__name"},
160                 {"UserName", "user_name"},
161                 {"User_Name", "user_name"},
162                 {"User__Name", "user__name"},
163                 {"_user_name", "user_name"},
164                 {"_UserName", "user_name"},
165                 {"_User_Name", "user_name"},
166                 {"UGLY_NAME", "ugly_name"},
167                 {"_Bars", "bars" },
168                 // [databind#1026]
169                 {"usId", "us_id" },
170                 {"uId", "u_id" },
171                 // [databind#2267]
172                 {"xCoordinate", "x_coordinate" },
173     });
174 
175     private ObjectMapper _lcWithUndescoreMapper;
176 
177     @Override
setUp()178     public void setUp() throws Exception
179     {
180         super.setUp();
181         _lcWithUndescoreMapper = new ObjectMapper();
182         _lcWithUndescoreMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
183     }
184 
185     /*
186     /**********************************************************
187     /* Test methods for SNAKE_CASE
188     /**********************************************************
189      */
190 
191     /**
192      * Unit test to verify translations of
193      * {@link PropertyNamingStrategy#SNAKE_CASE}
194      * outside the context of an ObjectMapper.
195      */
testLowerCaseStrategyStandAlone()196     public void testLowerCaseStrategyStandAlone()
197     {
198         for (Object[] pair : SNAKE_CASE_NAME_TRANSLATIONS) {
199             String translatedJavaName = PropertyNamingStrategy.SNAKE_CASE.nameForField(null, null,
200                     (String) pair[0]);
201             assertEquals((String) pair[1], translatedJavaName);
202         }
203     }
204 
testLowerCaseTranslations()205     public void testLowerCaseTranslations() throws Exception
206     {
207         // First serialize
208         String json = _lcWithUndescoreMapper.writeValueAsString(new PersonBean("Joe", "Sixpack", 42));
209         assertEquals("{\"first_name\":\"Joe\",\"last_name\":\"Sixpack\",\"age\":42}", json);
210 
211         // then deserialize
212         PersonBean result = _lcWithUndescoreMapper.readValue(json, PersonBean.class);
213         assertEquals("Joe", result.firstName);
214         assertEquals("Sixpack", result.lastName);
215         assertEquals(42, result.age);
216     }
217 
testLowerCaseAcronymsTranslations()218     public void testLowerCaseAcronymsTranslations() throws Exception
219     {
220         // First serialize
221         String json = _lcWithUndescoreMapper.writeValueAsString(new Acronyms("world wide web", "http://jackson.codehaus.org", "/path1/,/path2/"));
222         assertEquals("{\"www\":\"world wide web\",\"some_url\":\"http://jackson.codehaus.org\",\"some_uris\":\"/path1/,/path2/\"}", json);
223 
224         // then deserialize
225         Acronyms result = _lcWithUndescoreMapper.readValue(json, Acronyms.class);
226         assertEquals("world wide web", result.WWW);
227         assertEquals("http://jackson.codehaus.org", result.someURL);
228         assertEquals("/path1/,/path2/", result.someURIs);
229     }
230 
testLowerCaseOtherNonStandardNamesTranslations()231     public void testLowerCaseOtherNonStandardNamesTranslations() throws Exception
232     {
233         // First serialize
234         String json = _lcWithUndescoreMapper.writeValueAsString(new OtherNonStandardNames("Results", "_User", "___", "$User"));
235         assertEquals("{\"results\":\"Results\",\"user\":\"_User\",\"__\":\"___\",\"$_user\":\"$User\"}", json);
236 
237         // then deserialize
238         OtherNonStandardNames result = _lcWithUndescoreMapper.readValue(json, OtherNonStandardNames.class);
239         assertEquals("Results", result.Results);
240         assertEquals("_User", result._User);
241         assertEquals("___", result.___);
242         assertEquals("$User", result.$User);
243     }
244 
testLowerCaseUnchangedNames()245     public void testLowerCaseUnchangedNames() throws Exception
246     {
247         // First serialize
248         String json = _lcWithUndescoreMapper.writeValueAsString(new UnchangedNames("from_user", "_user", "from$user", "from7user", "_x"));
249         assertEquals("{\"from_user\":\"from_user\",\"user\":\"_user\",\"from$user\":\"from$user\",\"from7user\":\"from7user\",\"x\":\"_x\"}", json);
250 
251         // then deserialize
252         UnchangedNames result = _lcWithUndescoreMapper.readValue(json, UnchangedNames.class);
253         assertEquals("from_user", result.from_user);
254         assertEquals("_user", result._user);
255         assertEquals("from$user", result.from$user);
256         assertEquals("from7user", result.from7user);
257         assertEquals("_x", result._x);
258     }
259 
260     /*
261     /**********************************************************
262     /* Test methods for UPPER_CAMEL_CASE
263     /**********************************************************
264      */
265 
266     /**
267      * Unit test to verify translations of
268      * {@link PropertyNamingStrategy#UPPER_CAMEL_CASE }
269      * outside the context of an ObjectMapper.
270      */
testPascalCaseStandAlone()271     public void testPascalCaseStandAlone()
272     {
273         assertEquals("UserName", PropertyNamingStrategy.UPPER_CAMEL_CASE.nameForField(null, null, "userName"));
274         assertEquals("User", PropertyNamingStrategy.UPPER_CAMEL_CASE.nameForField(null, null, "User"));
275         assertEquals("User", PropertyNamingStrategy.UPPER_CAMEL_CASE.nameForField(null, null, "user"));
276         assertEquals("X", PropertyNamingStrategy.UPPER_CAMEL_CASE.nameForField(null, null, "x"));
277 
278         assertEquals("BADPublicName", PropertyNamingStrategy.UPPER_CAMEL_CASE.nameForField(null, null, "bADPublicName"));
279         assertEquals("BADPublicName", PropertyNamingStrategy.UPPER_CAMEL_CASE.nameForGetterMethod(null, null, "bADPublicName"));
280     }
281 
282     // [databind#428]
testIssue428PascalWithOverrides()283     public void testIssue428PascalWithOverrides() throws Exception
284     {
285         String json = new ObjectMapper()
286                 .setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE)
287                 .writeValueAsString(new Bean428());
288         if (!json.contains(quote("fooBar"))) {
289             fail("Should use name 'fooBar', does not: "+json);
290         }
291     }
292 
293     /*
294     /**********************************************************
295     /* Test methods for LOWER_CASE
296     /**********************************************************
297      */
298 
299     // For [databind#461]
testSimpleLowerCase()300     public void testSimpleLowerCase() throws Exception
301     {
302         final BoringBean input = new BoringBean();
303         ObjectMapper m = objectMapper();
304 
305         assertEquals(aposToQuotes("{'firstname':'Bob','lastname':'Burger'}"),
306                 m.writeValueAsString(input));
307     }
308 
309     /*
310     /**********************************************************
311     /* Test methods for KEBAB_CASE
312     /**********************************************************
313      */
314 
testKebabCaseStrategyStandAlone()315     public void testKebabCaseStrategyStandAlone()
316     {
317         assertEquals("some-value",
318                 PropertyNamingStrategy.KEBAB_CASE.nameForField(null, null, "someValue"));
319         assertEquals("some-value",
320                 PropertyNamingStrategy.KEBAB_CASE.nameForField(null, null, "SomeValue"));
321         assertEquals("url",
322                 PropertyNamingStrategy.KEBAB_CASE.nameForField(null, null, "URL"));
323         assertEquals("url-stuff",
324                 PropertyNamingStrategy.KEBAB_CASE.nameForField(null, null, "URLStuff"));
325         assertEquals("some-url-stuff",
326                 PropertyNamingStrategy.KEBAB_CASE.nameForField(null, null, "SomeURLStuff"));
327     }
328 
testSimpleKebabCase()329     public void testSimpleKebabCase() throws Exception
330     {
331         final FirstNameBean input = new FirstNameBean("Bob");
332         ObjectMapper m = new ObjectMapper()
333                 .setPropertyNamingStrategy(PropertyNamingStrategy.KEBAB_CASE);
334 
335         assertEquals(aposToQuotes("{'first-name':'Bob'}"), m.writeValueAsString(input));
336 
337         FirstNameBean result = m.readValue(aposToQuotes("{'first-name':'Billy'}"),
338                 FirstNameBean.class);
339         assertEquals("Billy", result.firstName);
340     }
341     /*
342     /**********************************************************
343     /* Test methods for LOWER_DOT_CASE
344     /**********************************************************
345      */
346 
testLowerCaseWithDotsStrategyStandAlone()347     public void testLowerCaseWithDotsStrategyStandAlone()
348     {
349         assertEquals("some.value",
350             PropertyNamingStrategy.LOWER_DOT_CASE.nameForField(null, null, "someValue"));
351         assertEquals("some.value",
352             PropertyNamingStrategy.LOWER_DOT_CASE.nameForField(null, null, "SomeValue"));
353         assertEquals("url",
354             PropertyNamingStrategy.LOWER_DOT_CASE.nameForField(null, null, "URL"));
355         assertEquals("url.stuff",
356             PropertyNamingStrategy.LOWER_DOT_CASE.nameForField(null, null, "URLStuff"));
357         assertEquals("some.url.stuff",
358             PropertyNamingStrategy.LOWER_DOT_CASE.nameForField(null, null, "SomeURLStuff"));
359     }
360 
testSimpleLowerCaseWithDots()361     public void testSimpleLowerCaseWithDots() throws Exception
362     {
363         final ObjectMapper m = jsonMapperBuilder()
364             .propertyNamingStrategy(PropertyNamingStrategy.LOWER_DOT_CASE)
365             .build();
366 
367         final FirstNameBean input = new FirstNameBean("Bob");
368         assertEquals(aposToQuotes("{'first.name':'Bob'}"), m.writeValueAsString(input));
369 
370         FirstNameBean result = m.readValue(aposToQuotes("{'first.name':'Billy'}"),
371                 FirstNameBean.class);
372         assertEquals("Billy", result.firstName);
373     }
374 
375     /*
376     /**********************************************************
377     /* Test methods, other
378     /**********************************************************
379      */
380 
381     /**
382      * Test [databind#815], problems with ObjectNode, naming strategy
383      */
testNamingWithObjectNode()384     public void testNamingWithObjectNode() throws Exception
385     {
386         ObjectMapper m = new ObjectMapper()
387             .setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CASE);
388         ClassWithObjectNodeField result =
389             m.readValue(
390                 "{ \"id\": \"1\", \"json\": { \"foo\": \"bar\", \"baz\": \"bing\" } }",
391                 ClassWithObjectNodeField.class);
392         assertNotNull(result);
393         assertEquals("1", result.id);
394         assertNotNull(result.json);
395         assertEquals(2, result.json.size());
396         assertEquals("bing", result.json.path("baz").asText());
397     }
398 
testExplicitRename()399     public void testExplicitRename() throws Exception
400     {
401         ObjectMapper m = jsonMapperBuilder()
402                 .propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
403                 .enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
404                 .build();
405         // by default, renaming will not take place on explicitly named fields
406         assertEquals(aposToQuotes("{'firstName':'Peter','lastName':'Venkman','user_age':'35'}"),
407                 m.writeValueAsString(new ExplicitBean()));
408 
409         m = jsonMapperBuilder()
410                 .propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
411                 .enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
412                 .enable(MapperFeature.ALLOW_EXPLICIT_PROPERTY_RENAMING)
413                 .build();
414         // w/ feature enabled, ALL property names should get re-written
415         assertEquals(aposToQuotes("{'first_name':'Peter','last_name':'Venkman','user_age':'35'}"),
416                 m.writeValueAsString(new ExplicitBean()));
417 
418         // test deserialization as well
419         ExplicitBean bean =
420                 m.readValue(aposToQuotes("{'first_name':'Egon','last_name':'Spengler','user_age':'32'}"),
421                         ExplicitBean.class);
422 
423         assertNotNull(bean);
424         assertEquals("Egon", bean.userFirstName);
425         assertEquals("Spengler", bean.userLastName);
426         assertEquals("32", bean.userAge);
427     }
428 
429     // Also verify that "no naming strategy" should be ok
testExplicitNoNaming()430     public void testExplicitNoNaming() throws Exception
431     {
432         ObjectMapper mapper = objectMapper();
433         String json = mapper.writeValueAsString(new DefaultNaming());
434         assertEquals(aposToQuotes("{'someValue':3}"), json);
435     }
436 }
437