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.impl;
017
018import org.joda.beans.Bean;
019import org.joda.beans.MetaProperty;
020import 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 */
033public 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 <P>  the property type
044     * @param bean  the bean that the property is bound to, not null
045     * @param metaProperty  the meta property, not null
046     * @return the property, not null
047     */
048    public static <P> BasicProperty<P> of(Bean bean, MetaProperty<P> metaProperty) {
049        return new BasicProperty<P>(bean, metaProperty);
050    }
051
052    /**
053     * Creates a property binding the bean to the meta-property.
054     * 
055     * @param bean  the bean that the property is bound to, not null
056     * @param metaProperty  the meta property, not null
057     */
058    private BasicProperty(Bean bean, MetaProperty<P> metaProperty) {
059        if (bean == null) {
060            throw new NullPointerException("Bean must not be null");
061        }
062        if (metaProperty == null) {
063            throw new NullPointerException("MetaProperty must not be null");
064        }
065        this.bean = bean;
066        this.metaProperty = metaProperty;
067    }
068
069    //-----------------------------------------------------------------------
070    @SuppressWarnings("unchecked")
071    @Override
072    public <B extends Bean> B bean() {
073        return (B) bean;
074    }
075
076    @Override
077    public MetaProperty<P> metaProperty() {
078        return metaProperty;
079    }
080
081    @Override
082    public String name() {
083        return metaProperty.name();
084    }
085
086    //-----------------------------------------------------------------------
087    @Override
088    public P get() {
089        return metaProperty.get(bean);
090    }
091
092    @Override
093    public void set(Object value) {
094        metaProperty.set(bean, value);
095    }
096
097    @Override
098    public P put(Object value) {
099        return metaProperty.put(bean, value);
100    }
101
102    //-----------------------------------------------------------------------
103    @Override
104    public boolean equals(Object obj) {
105        if (obj == this) {
106            return true;
107        }
108        if (obj instanceof Property) {
109            Property<?> other = (Property<?>) obj;
110            if (metaProperty.equals(other.metaProperty())) {
111                Object a = get();
112                Object b = other.get();
113                return a == null ? b == null : a.equals(b);
114            }
115        }
116        return false;
117    }
118
119    @Override
120    public int hashCode() {
121        P value = get();
122        return metaProperty.hashCode() ^ (value == null ? 0 : value.hashCode());
123    }
124
125    /**
126     * Returns a string that summarises the property.
127     * 
128     * @return a summary string, not null
129     */
130    @Override
131    public String toString() {
132        return metaProperty + "=" + get();
133    }
134
135}