001 /* $Id: BeanPropertySetterRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 020 package org.apache.commons.digester; 021 022 023 import java.beans.PropertyDescriptor; 024 025 import org.apache.commons.beanutils.BeanUtils; 026 import org.apache.commons.beanutils.DynaBean; 027 import org.apache.commons.beanutils.DynaProperty; 028 import org.apache.commons.beanutils.PropertyUtils; 029 030 031 /** 032 * <p> Rule implements sets a bean property on the top object 033 * to the body text.</p> 034 * 035 * <p> The property set:</p> 036 * <ul><li>can be specified when the rule is created</li> 037 * <li>or can match the current element when the rule is called.</li></ul> 038 * 039 * <p> Using the second method and the {@link ExtendedBaseRules} child match 040 * pattern, all the child elements can be automatically mapped to properties 041 * on the parent object.</p> 042 */ 043 044 public class BeanPropertySetterRule extends Rule { 045 046 047 // ----------------------------------------------------------- Constructors 048 049 050 /** 051 * <p>Construct rule that sets the given property from the body text.</p> 052 * 053 * @param digester associated <code>Digester</code> 054 * @param propertyName name of property to set 055 * 056 * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 057 * Use {@link #BeanPropertySetterRule(String propertyName)} instead. 058 */ 059 @Deprecated 060 public BeanPropertySetterRule(Digester digester, String propertyName) { 061 062 this(propertyName); 063 064 } 065 066 /** 067 * <p>Construct rule that automatically sets a property from the body text. 068 * 069 * <p> This construct creates a rule that sets the property 070 * on the top object named the same as the current element. 071 * 072 * @param digester associated <code>Digester</code> 073 * 074 * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 075 * Use {@link #BeanPropertySetterRule()} instead. 076 */ 077 @Deprecated 078 public BeanPropertySetterRule(Digester digester) { 079 080 this(); 081 082 } 083 084 /** 085 * <p>Construct rule that sets the given property from the body text.</p> 086 * 087 * @param propertyName name of property to set 088 */ 089 public BeanPropertySetterRule(String propertyName) { 090 091 this.propertyName = propertyName; 092 093 } 094 095 /** 096 * <p>Construct rule that automatically sets a property from the body text. 097 * 098 * <p> This construct creates a rule that sets the property 099 * on the top object named the same as the current element. 100 */ 101 public BeanPropertySetterRule() { 102 103 this((String)null); 104 105 } 106 107 // ----------------------------------------------------- Instance Variables 108 109 110 /** 111 * Set this property on the top object. 112 */ 113 protected String propertyName = null; 114 115 116 /** 117 * The body text used to set the property. 118 */ 119 protected String bodyText = null; 120 121 122 // --------------------------------------------------------- Public Methods 123 124 125 /** 126 * Process the body text of this element. 127 * 128 * @param namespace the namespace URI of the matching element, or an 129 * empty string if the parser is not namespace aware or the element has 130 * no namespace 131 * @param name the local name if the parser is namespace aware, or just 132 * the element name otherwise 133 * @param text The text of the body of this element 134 */ 135 @Override 136 public void body(String namespace, String name, String text) 137 throws Exception { 138 139 // log some debugging information 140 if (digester.log.isDebugEnabled()) { 141 digester.log.debug("[BeanPropertySetterRule]{" + 142 digester.match + "} Called with text '" + text + "'"); 143 } 144 145 bodyText = text.trim(); 146 147 } 148 149 150 /** 151 * Process the end of this element. 152 * 153 * @param namespace the namespace URI of the matching element, or an 154 * empty string if the parser is not namespace aware or the element has 155 * no namespace 156 * @param name the local name if the parser is namespace aware, or just 157 * the element name otherwise 158 * 159 * @exception NoSuchMethodException if the bean does not 160 * have a writeable property of the specified name 161 */ 162 @Override 163 public void end(String namespace, String name) throws Exception { 164 165 String property = propertyName; 166 167 if (property == null) { 168 // If we don't have a specific property name, 169 // use the element name. 170 property = name; 171 } 172 173 // Get a reference to the top object 174 Object top = digester.peek(); 175 176 // log some debugging information 177 if (digester.log.isDebugEnabled()) { 178 digester.log.debug("[BeanPropertySetterRule]{" + digester.match + 179 "} Set " + top.getClass().getName() + " property " + 180 property + " with text " + bodyText); 181 } 182 183 // Force an exception if the property does not exist 184 // (BeanUtils.setProperty() silently returns in this case) 185 if (top instanceof DynaBean) { 186 DynaProperty desc = 187 ((DynaBean) top).getDynaClass().getDynaProperty(property); 188 if (desc == null) { 189 throw new NoSuchMethodException 190 ("Bean has no property named " + property); 191 } 192 } else /* this is a standard JavaBean */ { 193 PropertyDescriptor desc = 194 PropertyUtils.getPropertyDescriptor(top, property); 195 if (desc == null) { 196 throw new NoSuchMethodException 197 ("Bean has no property named " + property); 198 } 199 } 200 201 // Set the property (with conversion as necessary) 202 BeanUtils.setProperty(top, property, bodyText); 203 204 } 205 206 207 /** 208 * Clean up after parsing is complete. 209 */ 210 @Override 211 public void finish() throws Exception { 212 213 bodyText = null; 214 215 } 216 217 218 /** 219 * Render a printable version of this Rule. 220 */ 221 @Override 222 public String toString() { 223 224 StringBuffer sb = new StringBuffer("BeanPropertySetterRule["); 225 sb.append("propertyName="); 226 sb.append(propertyName); 227 sb.append("]"); 228 return (sb.toString()); 229 230 } 231 232 }