001 // Copyright 2006, 2007, 2008, 2010, 2011 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry5.ioc.internal.services;
016
017 import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
018 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
019 import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
020 import org.apache.tapestry5.ioc.services.PropertyAdapter;
021
022 import java.beans.PropertyDescriptor;
023 import java.lang.reflect.Field;
024 import java.lang.reflect.Method;
025 import java.util.List;
026 import java.util.Map;
027
028 import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
029
030 public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
031 {
032 private final Map<String, PropertyAdapter> adapters = newCaseInsensitiveMap();
033
034 private final Class beanType;
035
036 public ClassPropertyAdapterImpl(Class beanType, List<PropertyDescriptor> descriptors)
037 {
038 this.beanType = beanType;
039
040 for (PropertyDescriptor pd : descriptors)
041 {
042 // Indexed properties will have a null propertyType (and a non-null
043 // indexedPropertyType). We ignore indexed properties.
044
045 if (pd.getPropertyType() == null)
046 continue;
047
048 Method readMethod = pd.getReadMethod();
049
050 Class propertyType = readMethod == null ? pd.getPropertyType() : GenericsUtils.extractGenericReturnType(
051 beanType, readMethod);
052
053 PropertyAdapter pa = new PropertyAdapterImpl(this, pd.getName(), propertyType, readMethod, pd
054 .getWriteMethod());
055
056 adapters.put(pa.getName(), pa);
057 }
058
059 // Now, add any public fields (even if static) that do not conflict
060
061 for (Field f : beanType.getFields())
062 {
063 String name = f.getName();
064
065 if (!adapters.containsKey(name))
066 {
067 Class propertyType = GenericsUtils.extractGenericFieldType(beanType, f);
068 PropertyAdapter pa = new PropertyAdapterImpl(this, name, propertyType, f);
069
070 adapters.put(name, pa);
071 }
072 }
073 }
074
075 public Class getBeanType()
076 {
077 return beanType;
078 }
079
080 @Override
081 public String toString()
082 {
083 String names = InternalUtils.joinSorted(adapters.keySet());
084
085 return String.format("<ClassPropertyAdaptor %s : %s>", beanType.getName(), names);
086 }
087
088 public List<String> getPropertyNames()
089 {
090 return InternalUtils.sortedKeys(adapters);
091 }
092
093 public PropertyAdapter getPropertyAdapter(String name)
094 {
095 return adapters.get(name);
096 }
097
098 public Object get(Object instance, String propertyName)
099 {
100 return adaptorFor(propertyName).get(instance);
101 }
102
103 public void set(Object instance, String propertyName, Object value)
104 {
105 adaptorFor(propertyName).set(instance, value);
106 }
107
108 private PropertyAdapter adaptorFor(String name)
109 {
110 PropertyAdapter pa = adapters.get(name);
111
112 if (pa == null)
113 throw new IllegalArgumentException(ServiceMessages.noSuchProperty(beanType, name));
114
115 return pa;
116 }
117
118 }