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 }