001 /* ======================================================================== 002 * JCommon : a free general purpose class library for the Java(tm) platform 003 * ======================================================================== 004 * 005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jcommon/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * -------------------------- 028 * BeanObjectDescription.java 029 * -------------------------- 030 * (C)opyright 2003-2005, by Thomas Morgner and Contributors. 031 * 032 * Original Author: Thomas Morgner; 033 * Contributor(s): David Gilbert (for Object Refinery Limited); 034 * 035 * $Id: BeanObjectDescription.java,v 1.6 2005/10/18 13:31:58 mungady Exp $ 036 * 037 * Changes (from 19-Feb-2003) 038 * ------------------------- 039 * 19-Feb-2003 : Added standard header and Javadocs (DG); 040 * 29-Apr-2003 : Distilled from the JFreeReport project and moved into 041 * JCommon (TM); 042 * 18-Aug-2005 : Added casts to suppress compiler warnings, as suggested in 043 * patch 1260622 (DG); 044 * 045 */ 046 047 package org.jfree.xml.factory.objects; 048 049 import java.lang.reflect.Method; 050 import java.lang.reflect.Modifier; 051 import java.util.Iterator; 052 import java.util.TreeSet; 053 import java.util.HashMap; 054 import java.beans.Introspector; 055 import java.beans.IntrospectionException; 056 import java.beans.BeanInfo; 057 import java.beans.PropertyDescriptor; 058 import java.io.ObjectInputStream; 059 import java.io.IOException; 060 061 import org.jfree.util.Log; 062 063 /** 064 * An object-description for a bean object. This object description 065 * is very dangerous, if the bean contains properties with undefined 066 * types. 067 * 068 * @author Thomas Morgner 069 */ 070 public class BeanObjectDescription extends AbstractObjectDescription { 071 072 private TreeSet ignoredParameters; 073 private transient HashMap properties; 074 075 /** 076 * Creates a new object description. 077 * 078 * @param className the class. 079 */ 080 public BeanObjectDescription(final Class className) { 081 this(className, true); 082 } 083 084 /** 085 * Creates a new object description. 086 * 087 * @param className the class. 088 * @param init set to true, to autmaoticly initialise the object 089 * description. If set to false, the initialisation is 090 * elsewhere. 091 */ 092 public BeanObjectDescription(final Class className, final boolean init) { 093 super(className); 094 // now create some method descriptions .. 095 this.ignoredParameters = new TreeSet(); 096 readBeanDescription(className, init); 097 } 098 099 private boolean isValidMethod (final Method method, final int parCount) 100 { 101 if (method == null) { 102 return false; 103 } 104 if (!Modifier.isPublic(method.getModifiers())) { 105 return false; 106 } 107 if (Modifier.isStatic(method.getModifiers())) { 108 return false; 109 } 110 if (method.getParameterTypes().length != parCount) { 111 return false; 112 } 113 return true; 114 } 115 116 /** 117 * Creates an object based on this description. 118 * 119 * @return The object. 120 */ 121 public Object createObject() { 122 try { 123 final Object o = getObjectClass().newInstance(); 124 // now add the various parameters ... 125 126 final Iterator it = getParameterNames(); 127 while (it.hasNext()) { 128 final String name = (String) it.next(); 129 130 if (isParameterIgnored(name)) { 131 continue; 132 } 133 134 final Method method = findSetMethod(name); 135 final Object parameterValue = getParameter(name); 136 if (parameterValue == null) { 137 // Log.debug ("Parameter: " + name + " is null"); 138 } 139 else { 140 method.invoke(o, new Object[]{parameterValue}); 141 } 142 } 143 return o; 144 } 145 catch (Exception e) { 146 Log.error("Unable to invoke bean method", e); 147 } 148 return null; 149 } 150 151 /** 152 * Finds a set method in the bean. 153 * 154 * @param parameterName the parameter name. 155 * 156 * @return The method. 157 */ 158 private Method findSetMethod(final String parameterName) { 159 final PropertyDescriptor descriptor 160 = (PropertyDescriptor) this.properties.get(parameterName); 161 return descriptor.getWriteMethod(); 162 } 163 164 /** 165 * Finds a get method in the bean. 166 * 167 * @param parameterName the paramater name. 168 * @return The method. 169 */ 170 private Method findGetMethod(final String parameterName) { 171 final PropertyDescriptor descriptor 172 = (PropertyDescriptor) this.properties.get(parameterName); 173 return descriptor.getReadMethod(); 174 } 175 176 /** 177 * Sets the parameters in the description to match the supplied object. 178 * 179 * @param o the object (<code>null</code> not allowed). 180 * 181 * @throws ObjectFactoryException if there is a problem. 182 */ 183 public void setParameterFromObject(final Object o) 184 throws ObjectFactoryException { 185 if (o == null) { 186 throw new NullPointerException("Given object is null"); 187 } 188 final Class c = getObjectClass(); 189 if (!c.isInstance(o)) { 190 throw new ObjectFactoryException("Object is no instance of " + c 191 + "(is " + o.getClass() + ")"); 192 } 193 194 final Iterator it = getParameterNames(); 195 while (it.hasNext()) { 196 final String propertyName = (String) it.next(); 197 198 if (isParameterIgnored(propertyName)) { 199 continue; 200 } 201 202 try { 203 final Method method = findGetMethod(propertyName); 204 final Object retval = method.invoke(o, (Object[]) null); 205 if (retval != null) { 206 setParameter(propertyName, retval); 207 } 208 } 209 catch (Exception e) { 210 Log.info("Exception on method invokation.", e); 211 } 212 213 } 214 } 215 216 /** 217 * Adds a parameter to the ignored parameters. 218 * 219 * @param parameter the parameter. 220 */ 221 protected void ignoreParameter(final String parameter) { 222 this.ignoredParameters.add (parameter); 223 } 224 225 /** 226 * Returns a flag that indicates whether or not the specified parameter is 227 * ignored. 228 * 229 * @param parameter the parameter. 230 * 231 * @return The flag. 232 */ 233 protected boolean isParameterIgnored (final String parameter) { 234 return this.ignoredParameters.contains(parameter); 235 } 236 237 private void readObject(final ObjectInputStream in) 238 throws IOException, ClassNotFoundException { 239 in.defaultReadObject(); 240 readBeanDescription(getObjectClass(), false); 241 } 242 243 private void readBeanDescription(final Class className, final boolean init) { 244 try { 245 this.properties = new HashMap(); 246 247 final BeanInfo bi = Introspector.getBeanInfo(className); 248 final PropertyDescriptor[] propertyDescriptors 249 = bi.getPropertyDescriptors(); 250 for (int i = 0; i < propertyDescriptors.length; i++) 251 { 252 final PropertyDescriptor propertyDescriptor = propertyDescriptors[i]; 253 final Method readMethod = propertyDescriptor.getReadMethod(); 254 final Method writeMethod = propertyDescriptor.getWriteMethod(); 255 if (isValidMethod(readMethod, 0) && isValidMethod(writeMethod, 1)) 256 { 257 final String name = propertyDescriptor.getName(); 258 this.properties.put(name, propertyDescriptor); 259 if (init) { 260 super.setParameterDefinition(name, 261 propertyDescriptor.getPropertyType()); 262 } 263 } 264 } 265 } 266 catch (IntrospectionException e) { 267 Log.error ("Unable to build bean description", e); 268 } 269 } 270 }