001    /*
002     *  Copyright 2001-2010 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     */
016    package org.joda.beans;
017    
018    import java.util.Map.Entry;
019    
020    /**
021     * A property that binds a {@code Bean} to a {@code MetaProperty}.
022     * <p>
023     * This is the standard implementation of a property.
024     * It defers the strategy of getting and setting the value to the meta-property.
025     * <p>
026     * This implementation is also a map entry to aid performance in {@code }
027     * 
028     * @param <B>  the type of the bean
029     * @param <P>  the type of the property content
030     * @author Stephen Colebourne
031     */
032    public final class StandardProperty<B, P> implements Property<B, P>, Entry<String, Property<B, P>> {
033    
034        /** The bean that the property is bound to. */
035        private final B bean;
036        /** The meta-property that the property is bound to. */
037        private final MetaProperty<B, P> metaProperty;
038    
039        /**
040         * Factory to create a property avoiding duplicate generics.
041         * 
042         * @param bean  the bean that the property is bound to, not null
043         * @param metaProperty  the meta property, not null
044         */
045        public static <B, P> StandardProperty<B, P> of(B bean, MetaProperty<B, P> metaProperty) {
046            return new StandardProperty<B, P>(bean, metaProperty);
047        }
048    
049        /**
050         * Creates a property binding the bean to the meta-property.
051         * 
052         * @param bean  the bean that the property is bound to, not null
053         * @param metaProperty  the meta property, not null
054         */
055        private StandardProperty(B bean, MetaProperty<B, P> metaProperty) {
056            Beans.checkNotNull(bean, "Bean must not be null");
057            Beans.checkNotNull(metaProperty, "MetaProperty must not be null");
058            this.bean = bean;
059            this.metaProperty = metaProperty;
060        }
061    
062        //-----------------------------------------------------------------------
063        @Override
064        public B bean() {
065            return bean;
066        }
067    
068        @Override
069        public MetaProperty<B, P> metaProperty() {
070            return metaProperty;
071        }
072    
073        //-----------------------------------------------------------------------
074        @Override
075        public P get() {
076            return metaProperty().get(bean());
077        }
078    
079        @Override
080        public void set(P value) {
081            metaProperty().set(bean(), value);
082        }
083    
084        //-----------------------------------------------------------------------
085        @Override
086        public String getKey() {
087            return metaProperty().name();
088        }
089    
090        @Override
091        public Property<B, P> getValue() {
092            return this;
093        }
094    
095        @Override
096        public Property<B, P> setValue(Property<B, P> value) {
097            throw new UnsupportedOperationException("Unmodifiable");
098        }
099    
100        //-----------------------------------------------------------------------
101        public boolean equals(Object obj) {
102            // specified by Map.Entry
103            if (obj instanceof Entry<?, ?>) {
104                Entry<?, ?> other = (Entry<?, ?>) obj;
105                return (this.getKey() == null ? other.getKey() == null : this.getKey().equals(other.getKey())) &&
106                    (this.getValue() == null ? other.getValue() == null : this.getValue().equals(other.getValue()));
107            }
108            return false;
109        }
110    
111        public int hashCode() {
112            // specified by Map.Entry
113            return (getKey()==null ? 0 : getKey().hashCode()) ^ (getValue()==null ? 0 : getValue().hashCode());
114        }
115    
116        /**
117         * Returns a string that summarizes the property.
118         * 
119         * @return a summary string, never null
120         */
121        @Override
122        public String toString() {
123            return metaProperty().name() + ":" + get();
124        }
125    
126    }