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;
019    
020    /**
021     * A meta-property using a {@code Map} for storage.
022     * <p>
023     * This meta-property uses a {@code Map} instead of a JavaBean to store the property.
024     * 
025     * @author Stephen Colebourne
026     */
027    public class MapMetaProperty<T> implements MetaProperty<Map<String, T>, T> {
028    
029        /** The map key, also known as the property name. */
030        private final String key;
031    
032        /**
033         * Constructor.
034         * 
035         * @param propertyName  the property name
036         */
037        public MapMetaProperty(String propertyName) {
038            super();
039            if (propertyName == null || propertyName.length() == 0) {
040                throw new IllegalArgumentException("Invalid property name: " + propertyName);
041            }
042            key = propertyName;
043        }
044    
045        //-----------------------------------------------------------------------
046        /**
047         * Creates a property that binds this meta property to a specific bean.
048         * 
049         * @param bean  the bean to create the bound property for
050         * @return the bound property
051         */
052        public Property<Map<String, T>, T> createProperty(Map<String, T> bean) {
053            return StandardProperty.of(bean, this);
054        }
055    
056        /**
057         * Gets the property name.
058         * 
059         * @return the name of the property
060         */
061        public String name() {
062            return key;
063        }
064    
065        /**
066         * Get the type of the property represented as a Class.
067         * 
068         * @return the type of the property
069         */
070        public Class<T> propertyClass() {
071            // isn't erasure horrible
072            return null;
073        }
074    
075        /**
076         * Get the type of the bean represented as a Class.
077         * 
078         * @return the type of the bean
079         */
080        @SuppressWarnings("unchecked")
081        public Class<Map<String, T>> beanClass() {
082            // if you think erasure is great, try fixing this
083            return (Class<Map<String, T>>) (Class) Map.class;
084        }
085    
086        /**
087         * Gets whether the property is read-write, read-only or write-only.
088         * 
089         * @return the property read-write type
090         */
091        public ReadWriteProperty readWrite() {
092            return ReadWriteProperty.READ_WRITE;
093        }
094    
095        //-----------------------------------------------------------------------
096        /**
097         * Gets the value of the bound property for the provided bean.
098         * <p>
099         * This is the equivalent to calling <code>getFoo()</code> on the bean itself.
100         * However some implementations of this interface may not require an actual get method.
101         * 
102         * @param bean  the bean to query, not null
103         * @return the value of the property on the bound bean
104         * @throws UnsupportedOperationException if the property is write-only
105         */
106        public T get(Map<String, T> bean) {
107            return bean.get(key);
108        }
109    
110        /**
111         * Sets the value of the bound property on the provided bean.
112         * <p>
113         * This is the equivalent to calling <code>setFoo()</code> on the bean itself.
114         * However some implementations of this interface may not require an actual set method.
115         * 
116         * @param bean  the bean to update, not null
117         * @param value  the value to set into the property on the bound bean
118         * @throws UnsupportedOperationException if the property is read-only
119         */
120        public void set(Map<String, T> bean, T value) {
121            bean.put(key, value);
122        }
123    
124        //-----------------------------------------------------------------------
125        /**
126         * Returns a debugging string.
127         * 
128         * @return a debugging string
129         */
130        @Override
131        public String toString() {
132            return "MetaProperty:" + name();
133        }
134    
135    }