001// Copyright 2006, 2007, 2008, 2010, 2011, 2012 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 015package org.apache.tapestry5.ioc.internal.services; 016 017import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap; 018 019import java.beans.PropertyDescriptor; 020import java.lang.annotation.Annotation; 021import java.lang.reflect.Field; 022import java.lang.reflect.Method; 023import java.util.List; 024import java.util.Map; 025 026import org.apache.tapestry5.ioc.internal.util.GenericsUtils; 027import org.apache.tapestry5.ioc.internal.util.InternalUtils; 028import org.apache.tapestry5.ioc.services.ClassPropertyAdapter; 029import org.apache.tapestry5.ioc.services.PropertyAdapter; 030 031public class ClassPropertyAdapterImpl implements ClassPropertyAdapter 032{ 033 private final Map<String, PropertyAdapter> adapters = newCaseInsensitiveMap(); 034 035 private final Class beanType; 036 037 public ClassPropertyAdapterImpl(Class beanType, List<PropertyDescriptor> descriptors) 038 { 039 this.beanType = beanType; 040 041 for (PropertyDescriptor pd : descriptors) 042 { 043 // Indexed properties will have a null propertyType (and a non-null 044 // indexedPropertyType). We ignore indexed properties. 045 046 if (pd.getPropertyType() == null) 047 continue; 048 049 Method readMethod = pd.getReadMethod(); 050 051 Class propertyType = readMethod == null ? pd.getPropertyType() : GenericsUtils.extractGenericReturnType( 052 beanType, readMethod); 053 054 PropertyAdapter pa = new PropertyAdapterImpl(this, pd.getName(), propertyType, readMethod, pd 055 .getWriteMethod()); 056 057 adapters.put(pa.getName(), pa); 058 } 059 060 // Now, add any public fields (even if static) that do not conflict 061 062 for (Field f : beanType.getFields()) 063 { 064 String name = f.getName(); 065 066 if (!adapters.containsKey(name)) 067 { 068 Class propertyType = GenericsUtils.extractGenericFieldType(beanType, f); 069 PropertyAdapter pa = new PropertyAdapterImpl(this, name, propertyType, f); 070 071 adapters.put(name, pa); 072 } 073 } 074 } 075 076 public Class getBeanType() 077 { 078 return beanType; 079 } 080 081 @Override 082 public String toString() 083 { 084 String names = InternalUtils.joinSorted(adapters.keySet()); 085 086 return String.format("<ClassPropertyAdaptor %s: %s>", beanType.getName(), names); 087 } 088 089 public List<String> getPropertyNames() 090 { 091 return InternalUtils.sortedKeys(adapters); 092 } 093 094 public PropertyAdapter getPropertyAdapter(String name) 095 { 096 return adapters.get(name); 097 } 098 099 public Object get(Object instance, String propertyName) 100 { 101 return adaptorFor(propertyName).get(instance); 102 } 103 104 public void set(Object instance, String propertyName, Object value) 105 { 106 adaptorFor(propertyName).set(instance, value); 107 } 108 109 public Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass) { 110 return adaptorFor(propertyName).getAnnotation(annotationClass); 111 } 112 113 private PropertyAdapter adaptorFor(String name) 114 { 115 PropertyAdapter pa = adapters.get(name); 116 117 if (pa == null) 118 throw new IllegalArgumentException(ServiceMessages.noSuchProperty(beanType, name)); 119 120 return pa; 121 } 122 123}