1 package com.randomnoun.common;
2
3 /* (c) 2013 randomnoun. All Rights Reserved. This work is licensed under a
4 * BSD Simplified License. (http://www.randomnoun.com/bsd-simplified.html)
5 */
6
7 import java.util.*;
8
9
10 /**
11 * This class is used to convert the Maps and Lists returned by Spring DAO into
12 * camelCase versions, which can be used when dealing with some databases
13 * that return all column names in upper case.
14 *
15 * <p>Maps and Lists passed to this object will be modified in-place.
16 *
17 * <p>This object should be considered thread-safe, i.e. many threads may use a
18 * single instance of this object at a time.
19 *
20 * @author knoxg
21 */
22 public class CamelCaser {
23
24
25
26 /** Internal map whose keys are ALLUPPERCASE text strings, and values are camelCase versions */
27 private Map<String, String> namingMap;
28
29 /**
30 * Create a new map renamer. The list supplied to this constructor contains
31 * a list of Strings that may be used as keys in the maps to be renamed. Each
32 * String is the camelCase version to return.
33 *
34 * @param nameList
35 */
36 public CamelCaser(List<String> nameList) {
37 this.populateNamingMap(nameList);
38 }
39
40 /**
41 * Creates a new CamelCaser object
42 *
43 * @param camelCaseNames A list of camelcased names, separated by commas.
44 *
45 * @throws NullPointerException if there was a problem loading the resource property list,
46 * or the propertyKey does not exist in the resource.
47 */
48 public CamelCaser(String camelCaseNames) {
49 List<String> nameList = new ArrayList<String>();
50 StringTokenizer tokenizer = new StringTokenizer(camelCaseNames, ",");
51 String token;
52
53 while (tokenizer.hasMoreElements()) {
54 token = tokenizer.nextToken();
55 nameList.add(token.trim());
56 }
57
58 populateNamingMap(nameList);
59 }
60
61 /** Private method used to create the namingMap object */
62 private void populateNamingMap(List<String> nameList) {
63 // don't croak if we're passed a null list
64 if (nameList == null) {
65 nameList = new ArrayList<String>(0);
66 }
67
68 namingMap = new HashMap<String, String>();
69
70 String name;
71
72 for (Iterator<String> i = nameList.iterator(); i.hasNext();) {
73 name = (String) i.next();
74 namingMap.put(name.toLowerCase(), name);
75 }
76 }
77
78 /** Renames an individual string. If the camelCase version of the string is not
79 * known, then it is returned without modification.
80 *
81 * @param string The String to be renamed
82 * @return The camelCase version of the String
83 */
84 public String renameString(String string) {
85 String result = (String) namingMap.get(string.toLowerCase());
86
87 if (result == null) {
88 result = string;
89 }
90
91 return result;
92 }
93
94 /** Renames all the keys in the map. The map may itself contain Maps and Lists,
95 * which will also be renamed.
96 *
97 * @param map The map to rename
98 */
99 @SuppressWarnings("unchecked")
100 public void renameMap(Map<String, Object> map) {
101 Object key;
102 Object value;
103 String newKey;
104
105
106 // we iterator on this object rather than map.keySet().iterator(),
107 // since we are modifying the keys in the map
108 // as we iterate.
109 List<String> keyList = new ArrayList<String>(map.keySet());
110
111 for (Iterator<String> i = keyList.iterator(); i.hasNext();) {
112 key = i.next();
113 value = map.get(key);
114
115 if (key instanceof String) {
116 newKey = renameString((String) key);
117 map.remove(key);
118 map.put(newKey, value);
119 }
120
121 // recurse through this structure
122 if (value instanceof Map) {
123 renameMap((Map<String, Object>) value);
124 } else if (value instanceof List) {
125 renameList((List<?>) value);
126 }
127 }
128 }
129
130 /** Renames all the objects in a list. Any Maps or Lists contained with the List
131 * will be recursed into.
132 *
133 * @param list The list containing maps to rename.
134 */
135 @SuppressWarnings("unchecked")
136 public void renameList(List<? extends Object> list) {
137 Object obj;
138
139 for (Iterator<? extends Object> i = list.iterator(); i.hasNext();) {
140 obj = i.next();
141
142 // recurse through this structure
143 if (obj instanceof Map) {
144 renameMap((Map<String, Object>) obj);
145 } else if (obj instanceof List) {
146 renameList((List<?>) obj);
147 }
148 }
149 }
150 }