001package com.randomnoun.common; 002 003/* (c) 2013 randomnoun. All Rights Reserved. This work is licensed under a 004 * BSD Simplified License. (http://www.randomnoun.com/bsd-simplified.html) 005 */ 006 007import java.util.*; 008 009 010/** 011 * This class is used to convert the Maps and Lists returned by Spring DAO into 012 * camelCase versions, which can be used when dealing with some databases 013 * that return all column names in upper case. 014 * 015 * <p>Maps and Lists passed to this object will be modified in-place. 016 * 017 * <p>This object should be considered thread-safe, i.e. many threads may use a 018 * single instance of this object at a time. 019 * 020 * @author knoxg 021 */ 022public class CamelCaser { 023 024 025 026 /** Internal map whose keys are ALLUPPERCASE text strings, and values are camelCase versions */ 027 private Map<String, String> namingMap; 028 029 /** 030 * Create a new map renamer. The list supplied to this constructor contains 031 * a list of Strings that may be used as keys in the maps to be renamed. Each 032 * String is the camelCase version to return. 033 * 034 * @param nameList 035 */ 036 public CamelCaser(List<String> nameList) { 037 this.populateNamingMap(nameList); 038 } 039 040 /** 041 * Creates a new CamelCaser object 042 * 043 * @param camelCaseNames A list of camelcased names, separated by commas. 044 * 045 * @throws NullPointerException if there was a problem loading the resource property list, 046 * or the propertyKey does not exist in the resource. 047 */ 048 public CamelCaser(String camelCaseNames) { 049 List<String> nameList = new ArrayList<String>(); 050 StringTokenizer tokenizer = new StringTokenizer(camelCaseNames, ","); 051 String token; 052 053 while (tokenizer.hasMoreElements()) { 054 token = tokenizer.nextToken(); 055 nameList.add(token.trim()); 056 } 057 058 populateNamingMap(nameList); 059 } 060 061 /** Private method used to create the namingMap object */ 062 private void populateNamingMap(List<String> nameList) { 063 // don't croak if we're passed a null list 064 if (nameList == null) { 065 nameList = new ArrayList<String>(0); 066 } 067 068 namingMap = new HashMap<String, String>(); 069 070 String name; 071 072 for (Iterator<String> i = nameList.iterator(); i.hasNext();) { 073 name = (String) i.next(); 074 namingMap.put(name.toLowerCase(), name); 075 } 076 } 077 078 /** Renames an individual string. If the camelCase version of the string is not 079 * known, then it is returned without modification. 080 * 081 * @param string The String to be renamed 082 * @return The camelCase version of the String 083 */ 084 public String renameString(String string) { 085 String result = (String) namingMap.get(string.toLowerCase()); 086 087 if (result == null) { 088 result = string; 089 } 090 091 return result; 092 } 093 094 /** Renames all the keys in the map. The map may itself contain Maps and Lists, 095 * which will also be renamed. 096 * 097 * @param map The map to rename 098 */ 099 @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}