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