001: /* ***** BEGIN LICENSE BLOCK *****
002: * Version: MPL 1.1
003: * The contents of this file are subject to the Mozilla Public License Version
004: * 1.1 (the "License"); you may not use this file except in compliance with
005: * the License. You may obtain a copy of the License at
006: * http://www.mozilla.org/MPL/
007: *
008: * Software distributed under the License is distributed on an "AS IS" basis,
009: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
010: * for the specific language governing rights and limitations under the
011: * License.
012: *
013: * The Original Code is Riot.
014: *
015: * The Initial Developer of the Original Code is
016: * Neteye GmbH.
017: * Portions created by the Initial Developer are Copyright (C) 2006
018: * the Initial Developer. All Rights Reserved.
019: *
020: * Contributor(s):
021: * Felix Gnass [fgnass at neteye dot de]
022: *
023: * ***** END LICENSE BLOCK ***** */
024: package org.riotfamily.common.beans;
025:
026: import java.beans.PropertyDescriptor;
027: import java.beans.PropertyEditor;
028: import java.lang.reflect.Method;
029: import java.util.HashMap;
030: import java.util.Map;
031: import java.util.regex.Matcher;
032: import java.util.regex.Pattern;
033:
034: import org.springframework.beans.BeanUtils;
035: import org.springframework.beans.FatalBeanException;
036: import org.springframework.util.Assert;
037: import org.springframework.util.ClassUtils;
038: import org.springframework.util.ReflectionUtils;
039: import org.springframework.util.StringUtils;
040:
041: /**
042: * Utility class to access bean properties via relection.
043: */
044: public final class PropertyUtils {
045:
046: private static DefaultPropertyEditorRegistry registry = new DefaultPropertyEditorRegistry();
047:
048: private static Pattern expressionPattern = Pattern
049: .compile("\\$\\{(.*?)\\}");
050:
051: private PropertyUtils() {
052: }
053:
054: public static Object getProperty(Object bean, String name) {
055: if (bean == null) {
056: return null;
057: }
058: ProtectedBeanWrapper wrapper = new ProtectedBeanWrapper(bean);
059: return wrapper.getPropertyValue(name);
060: }
061:
062: public static Object getProperty(Object bean, String name,
063: Class requiredType) {
064:
065: Object value = getProperty(bean, name);
066: if (value != null) {
067: Assert.isInstanceOf(requiredType, value);
068: }
069: return value;
070: }
071:
072: public static String getPropertyAsString(Object bean, String name) {
073: return convertToString(getProperty(bean, name));
074: }
075:
076: public static void setProperty(Object bean, String name,
077: Object value) {
078: ProtectedBeanWrapper wrapper = new ProtectedBeanWrapper(bean);
079: wrapper.setPropertyValue(name, value);
080: }
081:
082: public static void setPropertyAsString(Object bean, String name,
083: String s) {
084: Class type = getPropertyType(bean.getClass(), name);
085: Object value = convert(s, type);
086: setProperty(bean, name, value);
087: }
088:
089: /**
090: * Returns a Map containing the bean's properties.
091: * @since 6.4
092: */
093: public static Map getProperties(Object bean) {
094: PropertyDescriptor[] pd = BeanUtils.getPropertyDescriptors(bean
095: .getClass());
096: HashMap properties = new HashMap();
097: for (int i = 0; i < pd.length; i++) {
098: Object value = ReflectionUtils.invokeMethod(pd[i]
099: .getReadMethod(), bean);
100: properties.put(pd[i].getName(), value);
101: }
102: return properties;
103: }
104:
105: /**
106: * Returns a Map containing the bean's properties.
107: * @since 6.4
108: */
109: public static Map getProperties(Object bean, String[] propertyNames) {
110: HashMap properties = new HashMap();
111: for (int i = 0; i < propertyNames.length; i++) {
112: String name = propertyNames[i];
113: properties.put(name, getProperty(bean, name));
114: }
115: return properties;
116: }
117:
118: /**
119: * @since 6.4
120: */
121: public static String evaluate(String expression, Object bean) {
122: Matcher matcher = expressionPattern.matcher(expression);
123: StringBuffer sb = new StringBuffer();
124: while (matcher.find()) {
125: String property = matcher.group(1);
126: Object value = getProperty(bean, property);
127: matcher.appendReplacement(sb, convertToString(value));
128: }
129: matcher.appendTail(sb);
130: return sb.toString();
131: }
132:
133: public static Object convert(String s, Class targetClass) {
134: if (targetClass.equals(String.class)) {
135: return s;
136: }
137: PropertyEditor pe = registry.findEditor(targetClass);
138: Assert.notNull(pe, "No PropertyEditor found for class: "
139: + targetClass);
140: synchronized (pe) {
141: pe.setAsText(s);
142: return pe.getValue();
143: }
144: }
145:
146: /**
147: * @since 6.4
148: */
149: public static String convertToString(Object value) {
150: if (value != null) {
151: if (!(value instanceof String)) {
152: PropertyEditor pe = registry.findEditor(value
153: .getClass());
154: if (pe != null) {
155: synchronized (pe) {
156: pe.setValue(value);
157: return pe.getAsText();
158: }
159: }
160: }
161: return value.toString();
162: }
163: return null;
164: }
165:
166: /**
167: * @deprecated as of Riot 6.4, in favor of Spring's <code>BeanUtils.getPropertyDescriptor</code>.
168: */
169: public static PropertyDescriptor getPropertyDescriptor(Class clazz,
170: String property) {
171:
172: return BeanUtils.getPropertyDescriptor(clazz, property);
173: }
174:
175: public static Class getPropertyType(Class clazz, String property) {
176: PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(clazz,
177: property);
178: Assert.notNull(pd, "Property '" + property
179: + "' not found in class " + clazz);
180: return pd.getPropertyType();
181: }
182:
183: /**
184: * @since 6.4
185: */
186: public static Method findReadMethod(Class clazz, String property) {
187: String methodName = "get" + StringUtils.capitalize(property);
188: Method readMethod = BeanUtils.findDeclaredMethod(clazz,
189: methodName, null);
190: if (readMethod != null) {
191: readMethod.setAccessible(true);
192: }
193: return readMethod;
194: }
195:
196: /**
197: * @since 6.4
198: */
199: public static Method findWriteMethod(Class clazz, String property) {
200: String methodName = "set" + StringUtils.capitalize(property);
201: Method writeMethod = BeanUtils
202: .findDeclaredMethodWithMinimalParameters(clazz,
203: methodName);
204:
205: if (writeMethod != null) {
206: writeMethod.setAccessible(true);
207: }
208: return writeMethod;
209: }
210:
211: /**
212: * Returns the (super-)class where the given property is declared.
213: */
214: public static Class getDeclaringClass(Class clazz, String property) {
215:
216: PropertyDescriptor[] descriptors = BeanUtils
217: .getPropertyDescriptors(clazz);
218:
219: for (int i = 0; i < descriptors.length; i++) {
220: if (descriptors[i].getName().equals(property)) {
221: Method getter = descriptors[i].getReadMethod();
222: if (getter == null) {
223: return clazz;
224: }
225: return getter.getDeclaringClass();
226: }
227: }
228: return ClassUtils.getUserClass(clazz);
229: }
230:
231: /**
232: * Creates a new instance of the class specified by the given name.
233: * The method uses {@link ClassUtils#forName(String)} and
234: * {@link BeanUtils#instantiateClass(Class)} internally.
235: * ClassNotFoundExceptions are caught and re-thrown as
236: * {@link FatalBeanException}.
237: */
238: public static Object newInstance(String className) {
239: try {
240: Class clazz = ClassUtils.forName(className);
241: return BeanUtils.instantiateClass(clazz);
242: } catch (ClassNotFoundException e) {
243: throw new FatalBeanException(e.getMessage(), e);
244: }
245: }
246:
247: }
|