View Javadoc

1   /*
2    * $Id: MetaBeanProperty.java,v 1.6 2005/03/31 06:15:11 jstrachan Exp $
3    *
4    * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5    *
6    * Redistribution and use of this software and associated documentation
7    * ("Software"), with or without modification, are permitted provided that the
8    * following conditions are met:
9    *  1. Redistributions of source code must retain copyright statements and
10   * notices. Redistributions must also contain a copy of this document.
11   *  2. Redistributions in binary form must reproduce the above copyright
12   * notice, this list of conditions and the following disclaimer in the
13   * documentation and/or other materials provided with the distribution.
14   *  3. The name "groovy" must not be used to endorse or promote products
15   * derived from this Software without prior written permission of The Codehaus.
16   * For written permission, please contact info@codehaus.org.
17   *  4. Products derived from this Software may not be called "groovy" nor may
18   * "groovy" appear in their names without prior written permission of The
19   * Codehaus. "groovy" is a registered trademark of The Codehaus.
20   *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
21   *
22   * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
23   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25   * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
26   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32   * DAMAGE.
33   *
34   */
35  package groovy.lang;
36  
37  
38  import org.codehaus.groovy.runtime.InvokerHelper;
39  
40  /***
41   * Represents a property on a bean which may have a getter and/or a setter
42   *
43   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
44   * @author Kim Pilho
45   * @version $Revision: 1.6 $
46   */
47  public class MetaBeanProperty extends MetaProperty {
48  
49      private MetaMethod getter;
50      private MetaMethod setter;
51  
52      public MetaBeanProperty(String name, Class type, MetaMethod getter, MetaMethod setter) {
53          super(name, type);
54          this.getter = getter;
55          this.setter = setter;
56      }
57  
58      /***
59       * @return the property of the given object
60       * @throws Exception if the property could not be evaluated
61       */
62      public Object getProperty(Object object) throws Exception {
63          if (getter == null) {
64              //@todo we probably need a WriteOnlyException class
65              throw new GroovyRuntimeException("Cannot read write-only property: " + name);
66          }
67          return getter.invoke(object, MetaClass.EMPTY_ARRAY);
68      }
69  
70      /***
71       * Sets the property on the given object to the new value
72       *
73       * @param object   on which to set the property
74       * @param newValue the new value of the property
75       * @throws Exception if the property could not be set
76       */
77      public void setProperty(Object object, Object newValue) {
78          if (setter == null) {
79              throw new GroovyRuntimeException("Cannot set read-only property: " + name);
80          }
81  
82          try {
83              // we'll convert a GString to String if needed
84              if (getType() == String.class && !(newValue instanceof String)) {
85                  newValue = newValue.toString();
86              }
87  
88              // Set property for primitive types
89              if (newValue instanceof java.math.BigDecimal) {
90                  if (getType() == Double.class) {
91                      newValue = new Double(((java.math.BigDecimal) newValue).doubleValue());
92                  }
93                  else if (getType() == Float.class) {
94                      newValue = new Float(((java.math.BigDecimal) newValue).floatValue());
95                  }
96                  else if (getType() == Long.class) {
97                      newValue = new Long(((java.math.BigDecimal) newValue).longValue());
98                  }
99                  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 }