001/*
002 *  Copyright 2001-2013 Stephen Colebourne
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.joda.beans;
017
018import java.lang.annotation.Annotation;
019import java.lang.reflect.Type;
020import java.util.List;
021import java.util.NoSuchElementException;
022
023import org.joda.convert.StringConvert;
024
025/**
026 * A meta-property, defining those aspects of a property which are not specific
027 * to a particular bean, such as the property type and name.
028 * 
029 * @param <P>  the type of the property content
030 * @author Stephen Colebourne
031 */
032public interface MetaProperty<P> extends BeanQuery<P> {
033
034    /**
035     * Creates a property that binds this meta-property to a specific bean.
036     * 
037     * @param bean  the bean to create the property for, not null
038     * @return the property, not null
039     */
040    Property<P> createProperty(Bean bean);
041
042    //-----------------------------------------------------------------------
043    /**
044     * Gets the meta-bean which owns this meta-property.
045     * <p>
046     * Each meta-property is fully owned by a single bean.
047     * 
048     * @return the meta-bean, not null
049     */
050    MetaBean metaBean();
051
052    /**
053     * Gets the property name.
054     * <p>
055     * The JavaBean style methods getFoo() and setFoo() will lead to a property
056     * name of 'foo' and so on.
057     * 
058     * @return the name of the property, not empty
059     */
060    String name();
061
062    /**
063     * Get the type that declares the property, represented as a {@code Class}.
064     * 
065     * @return the type declaring the property, not null
066     */
067    Class<?> declaringType();
068
069    /**
070     * Get the type of the property represented as a {@code Class}.
071     * 
072     * @return the type of the property, not null
073     */
074    Class<P> propertyType();
075
076    /**
077     * Gets the generic types of the property.
078     * <p>
079     * This provides access to the generic type declared in the source code.
080     * 
081     * @return the full generic type of the property, unmodifiable, not null
082     */
083    Type propertyGenericType();
084
085    /**
086     * Gets whether the property is read-only, read-write or write-only.
087     * 
088     * @return the property read-write type, not null
089     */
090    PropertyReadWrite readWrite();
091
092    //-----------------------------------------------------------------------
093    /**
094     * Gets the annotations of the property.
095     * 
096     * @return the annotations, unmodifiable, not null
097     */
098    List<Annotation> annotations();
099
100    /**
101     * Gets a specified annotation of the property.
102     * 
103     * @param <A>  the annotation type
104     * @param annotation  the annotation class to find, not null
105     * @return the annotation, not null
106     * @throws NoSuchElementException if the annotation is not specified
107     */
108    <A extends Annotation> A annotation(Class<A> annotation);
109
110    //-----------------------------------------------------------------------
111    /**
112     * Gets the value of the property for the specified bean.
113     * <p>
114     * For a standard JavaBean, this is equivalent to calling <code>getFoo()</code> on the bean.
115     * Alternate implementations may perform any logic to obtain the value.
116     * 
117     * @param bean  the bean to query, not null
118     * @return the value of the property on the specified bean, may be null
119     * @throws ClassCastException if the bean is of an incorrect type
120     * @throws UnsupportedOperationException if the property is write-only
121     */
122    P get(Bean bean);
123
124    /**
125     * Sets the value of the property on the specified bean.
126     * <p>
127     * The value must be of the correct type for the property.
128     * For a standard JavaBean, this is equivalent to calling <code>setFoo()</code> on the bean.
129     * Alternate implementations may perform any logic to change the value.
130     * 
131     * @param bean  the bean to update, not null
132     * @param value  the value to set into the property on the specified bean, may be null
133     * @throws ClassCastException if the bean is of an incorrect type
134     * @throws ClassCastException if the value is of an invalid type for the property
135     * @throws UnsupportedOperationException if the property is read-only
136     * @throws RuntimeException if the value is rejected by the property (use appropriate subclasses)
137     */
138    void set(Bean bean, Object value);
139
140    /**
141     * Sets the value of the property on the associated bean and returns the previous value.
142     * <p>
143     * The value must be of the correct type for the property.
144     * This is a combination of the {@code get} and {@code set} methods that matches the definition
145     * of {@code put} in a {@code Map}.
146     * 
147     * @param bean  the bean to update, not null
148     * @param value  the value to set into the property on the specified bean, may be null
149     * @return the old value of the property, may be null
150     * @throws ClassCastException if the bean is of an incorrect type
151     * @throws ClassCastException if the value is of an invalid type for the property
152     * @throws UnsupportedOperationException if the property is read-only
153     * @throws RuntimeException if the value is rejected by the property (use appropriate subclasses)
154     */
155    P put(Bean bean, Object value);
156
157    //-----------------------------------------------------------------------
158    /**
159     * Gets the value of the property for the specified bean converted to a string.
160     * <p>
161     * This converts the result of {@link #get(Bean)} to a standard format string.
162     * Conversion uses Joda-Convert.
163     * Not all object types can be converted to a string, see Joda-Convert.
164     * <p>
165     * For a standard JavaBean, this is equivalent to calling <code>getFoo()</code> on the bean.
166     * Alternate implementations may perform any logic to obtain the value.
167     * 
168     * @param bean  the bean to query, not null
169     * @return the value of the property on the specified bean, may be null
170     * @throws ClassCastException if the bean is of an incorrect type
171     * @throws UnsupportedOperationException if the property is write-only
172     * @throws RuntimeException if the value cannot be converted to a string (use appropriate subclasses)
173     */
174    String getString(Bean bean);
175
176    /**
177     * Gets the value of the property for the specified bean converted to a string.
178     * <p>
179     * This converts the result of {@link #get(Bean)} to a standard format string using the supplied converter.
180     * Not all object types can be converted to a string, see Joda-Convert.
181     * <p>
182     * For a standard JavaBean, this is equivalent to calling <code>getFoo()</code> on the bean.
183     * Alternate implementations may perform any logic to obtain the value.
184     *
185     * @param bean  the bean to query, not null
186     * @param stringConvert  the converter to use, not null
187     * @return the value of the property on the specified bean, may be null
188     * @throws ClassCastException if the bean is of an incorrect type
189     * @throws UnsupportedOperationException if the property is write-only
190     * @throws RuntimeException if the value cannot be converted to a string (use appropriate subclasses)
191     */
192    String getString(Bean bean, StringConvert stringConvert);
193
194    /**
195     * Sets the value of the property on the specified bean from a string by conversion.
196     * <p>
197     * This converts the string to the correct type for the property and then sets it
198     * using {@link #set(Bean, Object)}. Conversion uses Joda-Convert.
199     * 
200     * @param bean  the bean to update, not null
201     * @param value  the value to set into the property on the specified bean, may be null
202     * @throws ClassCastException if the bean is of an incorrect type
203     * @throws ClassCastException if the value is of an invalid type for the property
204     * @throws UnsupportedOperationException if the property is read-only
205     * @throws RuntimeException if the value is rejected by the property (use appropriate subclasses)
206     */
207    void setString(Bean bean, String value);
208
209    /**
210     * Sets the value of the property on the specified bean from a string by conversion.
211     * <p>
212     * This converts the string to the correct type for the property using the supplied converter and then sets it
213     * using {@link #set(Bean, Object)}.
214     *
215     * @param bean  the bean to update, not null
216     * @param value  the value to set into the property on the specified bean, may be null
217     * @param stringConvert  the converter, not null
218     * @throws ClassCastException if the bean is of an incorrect type
219     * @throws ClassCastException if the value is of an invalid type for the property
220     * @throws UnsupportedOperationException if the property is read-only
221     * @throws RuntimeException if the value is rejected by the property (use appropriate subclasses)
222     */
223    void setString(Bean bean, String value, StringConvert stringConvert);
224
225    //-----------------------------------------------------------------------
226    /**
227     * Checks if this meta-property equals another.
228     * <p>
229     * This compares the property name and declaring type.
230     * It does not compare the property or bean types.
231     * 
232     * @param obj  the other meta-property, null returns false
233     * @return true if equal
234     */
235    @Override
236    boolean equals(Object obj);
237
238    /**
239     * Returns a suitable hash code.
240     * 
241     * @return the hash code
242     */
243    @Override
244    int hashCode();
245
246}