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.direct; 017 018import java.util.AbstractCollection; 019import java.util.AbstractMap; 020import java.util.AbstractSet; 021import java.util.Arrays; 022import java.util.Collection; 023import java.util.Iterator; 024import java.util.Map; 025import java.util.Set; 026 027import org.joda.beans.MetaProperty; 028 029/** 030 * A map of name to meta-property designed for use by {@code DirectBean}. 031 * <p> 032 * This meta-property map implementation is designed primarily for code-generation. 033 * It stores a reference to the meta-bean and the meta-properties. 034 * The meta-properties are accessed using {@link DirectMetaBean#metaPropertyGet(String)}. 035 * <p> 036 * This class is immutable and thread-safe. 037 * 038 * @author Stephen Colebourne 039 */ 040@SuppressWarnings("rawtypes") 041public final class DirectMetaPropertyMap implements Map<String, MetaProperty<?>> { 042 043 /** The meta-bean. */ 044 private final DirectMetaBean metaBean; 045 /** The property names. */ 046 private final Set<String> keys; 047 /** The meta-properties. */ 048 private final Collection<MetaProperty<?>> values; 049 /** The map entries. */ 050 private final Set<Entry<String, MetaProperty<?>>> entries; 051 052 /** 053 * Constructor. 054 * 055 * @param metaBean the meta-bean, not null 056 * @param parent the superclass parent, may be null 057 * @param propertyNames the property names, not null 058 */ 059 @SuppressWarnings("unchecked") 060 public DirectMetaPropertyMap(final DirectMetaBean metaBean, DirectMetaPropertyMap parent, String... propertyNames) { 061 if (metaBean == null) { 062 throw new NullPointerException("MetaBean must not be null"); 063 } 064 this.metaBean = metaBean; 065 int parentSize = 0; 066 final Entry<String, MetaProperty<?>>[] metaProperties; 067 if (parent != null) { 068 parentSize = parent.size(); 069 metaProperties = Arrays.copyOf(((Entries) parent.entries).metaProperties, parentSize + propertyNames.length); 070 } else { 071 metaProperties = new Entry[propertyNames.length]; 072 } 073 for (int i = 0; i < propertyNames.length; i++) { 074 metaProperties[i + parentSize] = new AbstractMap.SimpleImmutableEntry(propertyNames[i], metaBean.metaPropertyGet(propertyNames[i])); 075 } 076 keys = new Keys(metaProperties); 077 values = new Values(metaProperties); 078 entries = new Entries(metaProperties); 079 } 080 081 //----------------------------------------------------------------------- 082 @Override 083 public int size() { 084 return keys.size(); 085 } 086 087 @Override 088 public boolean isEmpty() { 089 return size() == 0; 090 } 091 092 @SuppressWarnings("unchecked") 093 @Override 094 public MetaProperty<Object> get(Object propertyName) { 095 if (propertyName instanceof String) { 096 return (MetaProperty<Object>) metaBean.metaPropertyGet((String) propertyName); 097 } 098 return null; 099 } 100 101 @Override 102 public boolean containsKey(Object propertyName) { 103 return propertyName instanceof String && 104 metaBean.metaPropertyGet(propertyName.toString()) != null; 105 } 106 107 @Override 108 public boolean containsValue(Object value) { 109 return value instanceof MetaProperty && 110 metaBean.metaPropertyGet(((MetaProperty<?>) value).name()) != null; 111 } 112 113 //----------------------------------------------------------------------- 114 @Override 115 public MetaProperty<?> put(String key, MetaProperty<?> value) { 116 throw new UnsupportedOperationException("DirectBean meta-property map cannot be modified"); 117 } 118 119 @Override 120 public MetaProperty<?> remove(Object key) { 121 throw new UnsupportedOperationException("DirectBean meta-property map cannot be modified"); 122 } 123 124 @Override 125 public void putAll(Map<? extends String, ? extends MetaProperty<?>> m) { 126 throw new UnsupportedOperationException("DirectBean meta-property map cannot be modified"); 127 } 128 129 @Override 130 public void clear() { 131 throw new UnsupportedOperationException("DirectBean meta-property map cannot be modified"); 132 } 133 134 //----------------------------------------------------------------------- 135 @Override 136 public Set<String> keySet() { 137 return keys; 138 } 139 140 @Override 141 public Collection<MetaProperty<?>> values() { 142 return values; 143 } 144 145 @Override 146 public Set<Entry<String, MetaProperty<?>>> entrySet() { 147 return entries; 148 } 149 150 //----------------------------------------------------------------------- 151 /** 152 * Collection implementation for the keys. 153 */ 154 private static final class Keys extends AbstractSet<String> { 155 private final Entry<String, MetaProperty<?>>[] metaProperties; 156 157 private Keys(Entry<String, MetaProperty<?>>[] metaProperties) { 158 this.metaProperties = metaProperties; 159 } 160 161 @Override 162 public Iterator<String> iterator() { 163 return new Iterator<String>() { 164 private int index; 165 @Override 166 public boolean hasNext() { 167 return index < metaProperties.length; 168 } 169 @Override 170 public String next() { 171 return metaProperties[index++].getKey(); 172 } 173 @Override 174 public void remove() { 175 throw new UnsupportedOperationException(); 176 } 177 }; 178 } 179 180 @Override 181 public int size() { 182 return metaProperties.length; 183 } 184 } 185 186 /** 187 * Collection implementation for the values. 188 */ 189 private static final class Values extends AbstractCollection<MetaProperty<?>> { 190 private final Entry<String, MetaProperty<?>>[] metaProperties; 191 192 private Values(Entry<String, MetaProperty<?>>[] metaProperties) { 193 this.metaProperties = metaProperties; 194 } 195 196 @Override 197 public Iterator<MetaProperty<?>> iterator() { 198 return new Iterator<MetaProperty<?>>() { 199 private int index; 200 @Override 201 public boolean hasNext() { 202 return index < metaProperties.length; 203 } 204 @Override 205 public MetaProperty<?> next() { 206 return metaProperties[index++].getValue(); 207 } 208 @Override 209 public void remove() { 210 throw new UnsupportedOperationException(); 211 } 212 }; 213 } 214 215 @Override 216 public int size() { 217 return metaProperties.length; 218 } 219 } 220 221 /** 222 * Collection implementation for the entries. 223 */ 224 private static final class Entries extends AbstractSet<Entry<String, MetaProperty<?>>> { 225 private final Entry<String, MetaProperty<?>>[] metaProperties; 226 227 private Entries(Entry<String, MetaProperty<?>>[] metaProperties) { 228 this.metaProperties = metaProperties; 229 } 230 231 @Override 232 public Iterator<Entry<String, MetaProperty<?>>> iterator() { 233 return new Iterator<Entry<String, MetaProperty<?>>>() { 234 private int index; 235 @Override 236 public boolean hasNext() { 237 return index < metaProperties.length; 238 } 239 @Override 240 public Entry<String, MetaProperty<?>> next() { 241 return metaProperties[index++]; 242 } 243 @Override 244 public void remove() { 245 throw new UnsupportedOperationException(); 246 } 247 }; 248 } 249 250 @Override 251 public int size() { 252 return metaProperties.length; 253 } 254 } 255 256}