View Javadoc

1   /*
2    *  Copyright 2001-2007 Stephen Colebourne
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.joda.beans;
17  
18  import java.beans.IntrospectionException;
19  import java.beans.PropertyDescriptor;
20  import java.lang.reflect.InvocationTargetException;
21  import java.lang.reflect.Method;
22  
23  /***
24   * A property is a field on a bean that can typically be called via get/set.
25   * 
26   * @author Stephen Colebourne
27   */
28  public class DescriptorMetaProperty<B, T> implements MetaProperty<B, T> {
29  
30      /*** The property descriptor. */
31      private final PropertyDescriptor descriptor;
32      /*** The type of the bean. */
33      private final Class<B> beanType;
34      /*** The read method. */
35      private final Method readMethod;
36      /*** The write method. */
37      private final Method writeMethod;
38  
39      /***
40       * Constructor.
41       * 
42       * @param beanType  the bean type
43       * @param propertyName  the property name
44       */
45      public DescriptorMetaProperty(Class<B> beanType, String propertyName) {
46          super();
47          try {
48              descriptor = new PropertyDescriptor(propertyName, beanType);
49          } catch (IntrospectionException ex) {
50              throw new NoSuchFieldError("Invalid property: " + propertyName);
51          }
52          Method readMethod = descriptor.getReadMethod();
53          Method writeMethod = descriptor.getWriteMethod();
54          if (readMethod == null & writeMethod == null) {
55              throw new NoSuchFieldError("Invalid property: " + propertyName);
56          }
57          this.readMethod = readMethod;
58          this.writeMethod = writeMethod;
59          this.beanType = beanType;
60      }
61  
62      //-----------------------------------------------------------------------
63      /***
64       * Creates a property that binds this meta property to a specific bean.
65       * 
66       * @param bean  the bean to create the bound property for
67       * @return the bound property
68       */
69      public Property<B, T> createProperty(B bean) {
70          return new SimpleProperty<B, T>(bean, this);
71      }
72  
73      /***
74       * Gets the property name.
75       * The JavaBean style methods getFoo() and setFoo() will lead 
76       * to a property name of 'foo' and so on.
77       * 
78       * @return the name of the property
79       */
80      public String getName() {
81          return descriptor.getName();
82      }
83  
84      /***
85       * Get the type of the property represented as a Class.
86       * 
87       * @return the type of the property
88       */
89      public Class<T> getType() {
90          // erasure is rubbish
91          return (Class<T>) descriptor.getPropertyType();
92      }
93  
94      /***
95       * Get the type of the bean represented as a Class.
96       * 
97       * @return the type of the bean
98       */
99      public Class<B> getBeanType() {
100         return beanType;
101     }
102 
103     /***
104      * Gets whether the property is read-write, read-only or write-only.
105      * 
106      * @return the property read-write type
107      */
108     public ReadWriteProperty getReadWrite() {
109         return (readMethod == null ? ReadWriteProperty.WRITE_ONLY :
110                 (writeMethod == null ? ReadWriteProperty.READ_ONLY : ReadWriteProperty.READ_WRITE));
111     }
112 
113     //-----------------------------------------------------------------------
114     /***
115      * Gets the value of the bound property for the provided bean.
116      * <p>
117      * This is the equivalent to calling <code>getFoo()</code> on the bean itself.
118      * However some implementations of this interface may not require an actual get method.
119      * 
120      * @param bean  the bean to query, not null
121      * @return the value of the property on the bound bean
122      * @throws UnsupportedOperationException if the property is write-only
123      */
124     @SuppressWarnings("unchecked")
125     public T get(B bean) {
126         if (getReadWrite().isReadable() == false) {
127             throw new UnsupportedOperationException("Property '" + getName() + "' cannot be read");
128         }
129         try {
130             return (T) readMethod.invoke(bean, (Object[]) null);
131         } catch (IllegalArgumentException ex) {
132             throw new UnsupportedOperationException("Property '" + getName() + "' cannot be read");
133         } catch (IllegalAccessException ex) {
134             throw new UnsupportedOperationException("Property '" + getName() + "' cannot be read");
135         } catch (InvocationTargetException ex) {
136             throw new UnsupportedOperationException("Property '" + getName() + "' cannot be read");
137         }
138     }
139 
140     /***
141      * Sets the value of the bound property on the provided bean.
142      * <p>
143      * This is the equivalent to calling <code>setFoo()</code> on the bean itself.
144      * However some implementations of this interface may not require an actual set method.
145      * 
146      * @param bean  the bean to update, not null
147      * @param value  the value to set into the property on the bound bean
148      * @throws UnsupportedOperationException if the property is read-only
149      */
150     public void set(B bean, T value) {
151         if (getReadWrite().isWritable() == false) {
152             throw new UnsupportedOperationException("Property '" + getName() + "' cannot be written");
153         }
154         try {
155             writeMethod.invoke(bean, value);
156         } catch (IllegalArgumentException ex) {
157             throw new UnsupportedOperationException("Property '" + getName() + "' cannot be read");
158         } catch (IllegalAccessException ex) {
159             throw new UnsupportedOperationException("Property '" + getName() + "' cannot be read");
160         } catch (InvocationTargetException ex) {
161             throw new UnsupportedOperationException("Property '" + getName() + "' cannot be read");
162         }
163     }
164 
165     //-----------------------------------------------------------------------
166     /***
167      * Returns a debugging string.
168      * 
169      * @return a debugging string
170      */
171     @Override
172     public String toString() {
173         return "MetaProperty:" + getName();
174     }
175 
176 }