001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.fusesource.hawtbuf.proto.compiler; 018 019 import java.beans.PropertyEditor; 020 import java.beans.PropertyEditorManager; 021 import java.io.File; 022 import java.lang.reflect.Field; 023 import java.lang.reflect.Method; 024 import java.lang.reflect.Modifier; 025 import java.net.URI; 026 import java.net.URISyntaxException; 027 import java.util.ArrayList; 028 import java.util.Arrays; 029 import java.util.HashMap; 030 import java.util.Iterator; 031 import java.util.LinkedHashMap; 032 import java.util.Map; 033 import java.util.Set; 034 import java.util.StringTokenizer; 035 import java.util.Map.Entry; 036 037 /** 038 * Support class used to do introspection/reflection based setting and getting of properties on a Java Bean. 039 * 040 * @author <a href="http://hiramchirino.com">Hiram Chirino</a> 041 */ 042 public final class IntrospectionSupport { 043 044 private IntrospectionSupport() { 045 } 046 047 public static boolean getProperties(Object target, Map props, String optionPrefix) { 048 049 boolean rc = false; 050 if (target == null) { 051 throw new IllegalArgumentException("target was null."); 052 } 053 if (props == null) { 054 throw new IllegalArgumentException("props was null."); 055 } 056 057 if (optionPrefix == null) { 058 optionPrefix = ""; 059 } 060 061 Class clazz = target.getClass(); 062 Method[] methods = clazz.getMethods(); 063 for (int i = 0; i < methods.length; i++) { 064 Method method = methods[i]; 065 String name = method.getName(); 066 Class type = method.getReturnType(); 067 Class params[] = method.getParameterTypes(); 068 if (name.startsWith("get") && params.length == 0 && type != null && isSettableType(type)) { 069 070 try { 071 072 Object value = method.invoke(target, new Object[] {}); 073 if (value == null) { 074 continue; 075 } 076 077 String strValue = convertToString(value, type); 078 if (strValue == null) { 079 continue; 080 } 081 082 name = name.substring(3, 4).toLowerCase() + name.substring(4); 083 props.put(optionPrefix + name, strValue); 084 rc = true; 085 086 } catch (Throwable ignore) { 087 } 088 089 } 090 } 091 092 return rc; 093 } 094 095 public static boolean setProperties(Object target, Map<String, ?> props, String optionPrefix) { 096 boolean rc = false; 097 if (target == null) { 098 throw new IllegalArgumentException("target was null."); 099 } 100 if (props == null) { 101 throw new IllegalArgumentException("props was null."); 102 } 103 104 for (Iterator<String> iter = props.keySet().iterator(); iter.hasNext();) { 105 String name = iter.next(); 106 if (name.startsWith(optionPrefix)) { 107 Object value = props.get(name); 108 name = name.substring(optionPrefix.length()); 109 if (setProperty(target, name, value)) { 110 iter.remove(); 111 rc = true; 112 } 113 } 114 } 115 return rc; 116 } 117 118 public static Map<String, Object> extractProperties(Map props, String optionPrefix) { 119 if (props == null) { 120 throw new IllegalArgumentException("props was null."); 121 } 122 123 HashMap<String, Object> rc = new HashMap<String, Object>(props.size()); 124 125 for (Iterator iter = props.keySet().iterator(); iter.hasNext();) { 126 String name = (String)iter.next(); 127 if (name.startsWith(optionPrefix)) { 128 Object value = props.get(name); 129 name = name.substring(optionPrefix.length()); 130 rc.put(name, value); 131 iter.remove(); 132 } 133 } 134 135 return rc; 136 } 137 138 public static boolean setProperties(Object target, Map props) { 139 boolean rc = false; 140 141 if (target == null) { 142 throw new IllegalArgumentException("target was null."); 143 } 144 if (props == null) { 145 throw new IllegalArgumentException("props was null."); 146 } 147 148 for (Iterator iter = props.entrySet().iterator(); iter.hasNext();) { 149 Map.Entry entry = (Entry)iter.next(); 150 if (setProperty(target, (String)entry.getKey(), entry.getValue())) { 151 iter.remove(); 152 rc = true; 153 } 154 } 155 156 return rc; 157 } 158 159 public static boolean setProperty(Object target, String name, Object value) { 160 try { 161 Class clazz = target.getClass(); 162 Method setter = findSetterMethod(clazz, name); 163 if (setter == null) { 164 return false; 165 } 166 167 // If the type is null or it matches the needed type, just use the 168 // value directly 169 if (value == null || value.getClass() == setter.getParameterTypes()[0]) { 170 setter.invoke(target, new Object[] {value}); 171 } else { 172 // We need to convert it 173 setter.invoke(target, new Object[] {convert(value, setter.getParameterTypes()[0])}); 174 } 175 return true; 176 } catch (Throwable ignore) { 177 return false; 178 } 179 } 180 181 private static Object convert(Object value, Class type) throws URISyntaxException { 182 PropertyEditor editor = PropertyEditorManager.findEditor(type); 183 if (editor != null) { 184 editor.setAsText(value.toString()); 185 return editor.getValue(); 186 } 187 if (type == URI.class) { 188 return new URI(value.toString()); 189 } 190 if (type == File.class) { 191 return new File(value.toString()); 192 } 193 if (type == File[].class) { 194 ArrayList<File> files = new ArrayList<File>(); 195 StringTokenizer st = new StringTokenizer(value.toString(), ":"); 196 while(st.hasMoreTokens()) { 197 String t = st.nextToken(); 198 if( t!=null && t.trim().length()>0 ) { 199 files.add(new File(t.trim())); 200 } 201 } 202 File rc[] = new File[files.size()]; 203 files.toArray(rc); 204 return rc; 205 } 206 return null; 207 } 208 209 private static String convertToString(Object value, Class type) throws URISyntaxException { 210 PropertyEditor editor = PropertyEditorManager.findEditor(type); 211 if (editor != null) { 212 editor.setValue(value); 213 return editor.getAsText(); 214 } 215 if (type == URI.class) { 216 return ((URI)value).toString(); 217 } 218 return null; 219 } 220 221 private static Method findSetterMethod(Class clazz, String name) { 222 // Build the method name. 223 name = "set" + name.substring(0, 1).toUpperCase() + name.substring(1); 224 Method[] methods = clazz.getMethods(); 225 for (int i = 0; i < methods.length; i++) { 226 Method method = methods[i]; 227 Class params[] = method.getParameterTypes(); 228 if (method.getName().equals(name) && params.length == 1 && isSettableType(params[0])) { 229 return method; 230 } 231 } 232 return null; 233 } 234 235 private static boolean isSettableType(Class clazz) { 236 if (PropertyEditorManager.findEditor(clazz) != null) { 237 return true; 238 } 239 if (clazz == URI.class) { 240 return true; 241 } 242 if (clazz == File.class) { 243 return true; 244 } 245 if (clazz == File[].class) { 246 return true; 247 } 248 if (clazz == Boolean.class) { 249 return true; 250 } 251 return false; 252 } 253 254 public static String toString(Object target) { 255 return toString(target, Object.class); 256 } 257 258 public static String toString(Object target, Class stopClass) { 259 LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>(); 260 addFields(target, target.getClass(), stopClass, map); 261 StringBuffer buffer = new StringBuffer(simpleName(target.getClass())); 262 buffer.append(" {"); 263 Set entrySet = map.entrySet(); 264 boolean first = true; 265 for (Iterator iter = entrySet.iterator(); iter.hasNext();) { 266 Map.Entry entry = (Map.Entry)iter.next(); 267 if (first) { 268 first = false; 269 } else { 270 buffer.append(", "); 271 } 272 buffer.append(entry.getKey()); 273 buffer.append(" = "); 274 appendToString(buffer, entry.getValue()); 275 } 276 buffer.append("}"); 277 return buffer.toString(); 278 } 279 280 protected static void appendToString(StringBuffer buffer, Object value) { 281 buffer.append(value); 282 } 283 284 public static String simpleName(Class clazz) { 285 String name = clazz.getName(); 286 int p = name.lastIndexOf("."); 287 if (p >= 0) { 288 name = name.substring(p + 1); 289 } 290 return name; 291 } 292 293 private static void addFields(Object target, Class startClass, Class<Object> stopClass, LinkedHashMap<String, Object> map) { 294 295 if (startClass != stopClass) { 296 addFields(target, startClass.getSuperclass(), stopClass, map); 297 } 298 299 Field[] fields = startClass.getDeclaredFields(); 300 for (int i = 0; i < fields.length; i++) { 301 Field field = fields[i]; 302 if (Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers()) 303 || Modifier.isPrivate(field.getModifiers())) { 304 continue; 305 } 306 307 try { 308 field.setAccessible(true); 309 Object o = field.get(target); 310 if (o != null && o.getClass().isArray()) { 311 try { 312 o = Arrays.asList((Object[])o); 313 } catch (Throwable e) { 314 } 315 } 316 map.put(field.getName(), o); 317 } catch (Throwable e) { 318 e.printStackTrace(); 319 } 320 } 321 322 } 323 324 }