001 /*
002 * $Id: MetaBeanProperty.java,v 1.6 2005/03/31 06:15:11 jstrachan Exp $
003 *
004 * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005 *
006 * Redistribution and use of this software and associated documentation
007 * ("Software"), with or without modification, are permitted provided that the
008 * following conditions are met:
009 * 1. Redistributions of source code must retain copyright statements and
010 * notices. Redistributions must also contain a copy of this document.
011 * 2. Redistributions in binary form must reproduce the above copyright
012 * notice, this list of conditions and the following disclaimer in the
013 * documentation and/or other materials provided with the distribution.
014 * 3. The name "groovy" must not be used to endorse or promote products
015 * derived from this Software without prior written permission of The Codehaus.
016 * For written permission, please contact info@codehaus.org.
017 * 4. Products derived from this Software may not be called "groovy" nor may
018 * "groovy" appear in their names without prior written permission of The
019 * Codehaus. "groovy" is a registered trademark of The Codehaus.
020 * 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
021 *
022 * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
023 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
024 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
025 * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
026 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
027 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
028 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
029 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
030 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
031 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
032 * DAMAGE.
033 *
034 */
035 package groovy.lang;
036
037
038 import org.codehaus.groovy.runtime.InvokerHelper;
039
040 /**
041 * Represents a property on a bean which may have a getter and/or a setter
042 *
043 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
044 * @author Kim Pilho
045 * @version $Revision: 1.6 $
046 */
047 public class MetaBeanProperty extends MetaProperty {
048
049 private MetaMethod getter;
050 private MetaMethod setter;
051
052 public MetaBeanProperty(String name, Class type, MetaMethod getter, MetaMethod setter) {
053 super(name, type);
054 this.getter = getter;
055 this.setter = setter;
056 }
057
058 /**
059 * @return the property of the given object
060 * @throws Exception if the property could not be evaluated
061 */
062 public Object getProperty(Object object) throws Exception {
063 if (getter == null) {
064 //@todo we probably need a WriteOnlyException class
065 throw new GroovyRuntimeException("Cannot read write-only property: " + name);
066 }
067 return getter.invoke(object, MetaClass.EMPTY_ARRAY);
068 }
069
070 /**
071 * Sets the property on the given object to the new value
072 *
073 * @param object on which to set the property
074 * @param newValue the new value of the property
075 * @throws Exception if the property could not be set
076 */
077 public void setProperty(Object object, Object newValue) {
078 if (setter == null) {
079 throw new GroovyRuntimeException("Cannot set read-only property: " + name);
080 }
081
082 try {
083 // we'll convert a GString to String if needed
084 if (getType() == String.class && !(newValue instanceof String)) {
085 newValue = newValue.toString();
086 }
087
088 // Set property for primitive types
089 if (newValue instanceof java.math.BigDecimal) {
090 if (getType() == Double.class) {
091 newValue = new Double(((java.math.BigDecimal) newValue).doubleValue());
092 }
093 else if (getType() == Float.class) {
094 newValue = new Float(((java.math.BigDecimal) newValue).floatValue());
095 }
096 else if (getType() == Long.class) {
097 newValue = new Long(((java.math.BigDecimal) newValue).longValue());
098 }
099 else if (getType() == Integer.class) {
100 newValue = new Integer(((java.math.BigDecimal) newValue).intValue());
101 }
102 else if (getType() == Short.class) {
103 newValue = new Short((short) ((java.math.BigDecimal) newValue).intValue());
104 }
105 else if (getType() == Byte.class) {
106 newValue = new Byte((byte) ((java.math.BigDecimal) newValue).intValue());
107 }
108 else if (getType() == Character.class) {
109 newValue = new Character((char) ((java.math.BigDecimal) newValue).intValue());
110 }
111 }
112 else if (newValue instanceof java.math.BigInteger) {
113 if (getType() == Long.class) {
114 newValue = new Long(((java.math.BigInteger) newValue).longValue());
115 }
116 else if (getType() == Integer.class) {
117 newValue = new Integer(((java.math.BigInteger) newValue).intValue());
118 }
119 else if (getType() == Short.class) {
120 newValue = new Short((short) ((java.math.BigInteger) newValue).intValue());
121 }
122 else if (getType() == Byte.class) {
123 newValue = new Byte((byte) ((java.math.BigInteger) newValue).intValue());
124 }
125 else if (getType() == Character.class) {
126 newValue = new Character((char) ((java.math.BigInteger) newValue).intValue());
127 }
128 }
129 else if (newValue instanceof java.lang.Long) {
130 if (getType() == Integer.class) {
131 newValue = new Integer(((Long) newValue).intValue());
132 }
133 else if (getType() == Short.class) {
134 newValue = new Short(((Long) newValue).shortValue());
135 }
136 else if (getType() == Byte.class) {
137 newValue = new Byte(((Long) newValue).byteValue());
138 }
139 else if (getType() == Character.class) {
140 newValue = new Character((char) ((Long) newValue).intValue());
141 }
142 }
143 else if (newValue instanceof java.lang.Integer) {
144 if (getType() == Short.class) {
145 newValue = new Short(((Integer) newValue).shortValue());
146 }
147 else if (getType() == Byte.class) {
148 newValue = new Byte(((Integer) newValue).byteValue());
149 }
150 else if (getType() == Character.class) {
151 newValue = new Character((char) ((Integer) newValue).intValue());
152 }
153 }
154
155 setter.invoke(object, new Object[]{newValue});
156 }
157 catch (IllegalArgumentException e) { // exception for executing as scripts
158 try {
159 newValue = InvokerHelper.asType(newValue, getType());
160 setter.invoke(object, new Object[]{newValue});
161 }
162 catch (Exception ex) {
163 throw new TypeMismatchException("The property '" + toName(object.getClass()) + "." + name
164 + "' can not refer to the value '"
165 + newValue + "' (type " + toName(newValue.getClass())
166 + "), because it is of the type " + toName(getType())
167 + ". The reason is from java.lang.IllegalArgumentException.");
168 }
169 }
170 catch (ClassCastException e) { // exception for executing as compiled classes
171 try {
172 newValue = InvokerHelper.asType(newValue, getType());
173 setter.invoke(object, new Object[]{newValue});
174 }
175 catch (Exception ex) {
176 throw new TypeMismatchException("The property '" + toName(object.getClass()) + "." + name
177 + "' can not refer to the value '"
178 + newValue + "' (type " + toName(newValue.getClass())
179 + "), because it is of the type " + toName(getType())
180 + ". The reason is from java.lang.ClassCastException.");
181 }
182 }
183 catch (Exception e) {
184 throw new GroovyRuntimeException("Cannot set property: " + name +
185 " reason: " + e.getMessage(), e);
186 }
187 }
188
189 private String toName(Class c) {
190 String s = c.toString();
191 if (s.startsWith("class ") && s.length() > 6) {
192 return s.substring(6);
193 }
194 else {
195 return s;
196 }
197 }
198
199 public MetaMethod getGetter() {
200 return getter;
201 }
202
203 public MetaMethod getSetter() {
204 return setter;
205 }
206
207 /**
208 * this is for MetaClass to patch up the object later when looking for get*() methods
209 */
210 void setGetter(MetaMethod getter) {
211 this.getter = getter;
212 }
213
214 /**
215 * this is for MetaClass to patch up the object later when looking for set*() methods
216 */
217 void setSetter(MetaMethod setter) {
218 this.setter = setter;
219 }
220 }