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 java.lang.annotation.Annotation;
019import java.util.List;
020import java.util.NoSuchElementException;
021
022import org.joda.beans.Bean;
023import org.joda.beans.JodaBeanUtils;
024import org.joda.beans.MetaProperty;
025import org.joda.beans.Property;
026import org.joda.convert.StringConvert;
027
028/**
029 * An abstract base meta-property.
030 * 
031 * @param <P>  the type of the property content
032 * @author Stephen Colebourne
033 */
034public abstract class BasicMetaProperty<P> implements MetaProperty<P> {
035
036    /** The name of the property. */
037    private final String name;
038
039    /**
040     * Constructor.
041     * 
042     * @param propertyName  the property name, not empty
043     */
044    protected BasicMetaProperty(String propertyName) {
045        if (propertyName == null || propertyName.length() == 0) {
046            throw new NullPointerException("Property name must not be null or empty");
047        }
048        this.name = propertyName;
049    }
050
051    //-----------------------------------------------------------------------
052    @Override
053    public Property<P> createProperty(Bean bean) {
054        return BasicProperty.of(bean, this);
055    }
056
057    @Override
058    public String name() {
059        return name;
060    }
061
062    //-----------------------------------------------------------------------
063    @Override
064    public P put(Bean bean, Object value) {
065        P old = get(bean);
066        set(bean, value);
067        return old;
068    }
069
070    //-----------------------------------------------------------------------
071    @Override
072    public String getString(Bean bean) {
073        return getString(bean, JodaBeanUtils.stringConverter());
074    }
075
076    @Override
077    public String getString(Bean bean, StringConvert stringConvert) {
078        P value = get(bean);
079        return stringConvert.convertToString(propertyType(), value);
080    }
081
082    @Override
083    public void setString(Bean bean, String value) {
084        setString(bean, value, JodaBeanUtils.stringConverter());
085    }
086
087    @Override
088    public void setString(Bean bean, String value, StringConvert stringConvert) {
089        set(bean, stringConvert.convertFromString(propertyType(), value));
090    }
091
092    //-----------------------------------------------------------------------
093    @SuppressWarnings("unchecked")
094    @Override
095    public <A extends Annotation> A annotation(Class<A> annotationClass) {
096        List<Annotation> annotations = annotations();
097        for (Annotation annotation : annotations) {
098            if (annotationClass.isInstance(annotation)) {
099                return (A) annotation;
100            }
101        }
102        throw new NoSuchElementException("Unknown annotation: " + annotationClass.getName());
103    }
104
105    //-----------------------------------------------------------------------
106    @Override
107    public boolean equals(Object obj) {
108        if (obj instanceof MetaProperty<?>) {
109            MetaProperty<?> other = (MetaProperty<?>) obj;
110            return name().equals(other.name()) && declaringType().equals(other.declaringType());
111        }
112        return false;
113    }
114
115    @Override
116    public int hashCode() {
117        return name().hashCode() ^ declaringType().hashCode();
118    }
119
120    /**
121     * Returns a string that summarises the meta-property.
122     * 
123     * @return a summary string, not null
124     */
125    @Override
126    public String toString() {
127        return declaringType().getSimpleName() + ":" + name();
128    }
129
130}