001 /*
002 Copyright (c) 2009 Olivier Chafik, All Rights Reserved
003
004 This file is part of JNAerator (http://jnaerator.googlecode.com/).
005
006 JNAerator is free software: you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation, either version 3 of the License, or
009 (at your option) any later version.
010
011 JNAerator is distributed in the hope that it will be useful,
012 but WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 GNU General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with JNAerator. If not, see <http://www.gnu.org/licenses/>.
018 */
019 package com.ochafik.lang.reflect;
020
021 //import static org.junit.Assert.assertNull;
022 //import static org.junit.Assert.assertTrue;
023
024 import java.lang.reflect.Field;
025 import java.lang.reflect.Method;
026 import java.lang.reflect.Type;
027 import java.util.HashMap;
028 import java.util.Map;
029 import java.util.Set;
030 import java.util.regex.Pattern;
031
032 import com.ochafik.util.string.RegexUtils;
033 import com.ochafik.util.string.StringUtils;
034
035 public class GettersAndSettersHelper {
036 public static class GetterAndSetterInfo {
037 public Method getter;
038 public Method setter;
039 //public Field field;
040 public String fieldName;
041 public boolean isFull() {
042 return getter != null && setter != null;
043 }
044 public Class<?> elementType;
045 public GetterAndSetterInfo(String fieldName, Class<?> elementType, Method getter, Method setter, Field field) {
046 this.elementType = elementType;
047 this.fieldName = fieldName;
048 this.getter = getter;
049 this.setter = setter;
050 //this.field = field;
051 }
052 public GetterAndSetterInfo() {}
053 public boolean isConsistent() {
054 if (getter == null || setter == null)
055 return true;
056
057 Class<?>[] pts = setter.getParameterTypes();
058 return pts.length == 1 && pts[0].isAssignableFrom(getter.getReturnType());
059 }
060 }
061
062 public final Map<String, GetterAndSetterInfo> gettersAndSetters = new HashMap<String, GetterAndSetterInfo>();
063
064 static Pattern getterSetterPattern = Pattern.compile("(is|get|set)([A-Z]\\w+)");
065
066 public GettersAndSettersHelper(Class<?> type, FieldGetter fieldGetter) {
067 this.fieldGetter = fieldGetter;
068 for (Method method : type.getMethods()) {
069 int nParams = method.getParameterTypes().length;
070 if (nParams > 1)
071 continue;
072
073 String name = method.getName();
074 String match[] = RegexUtils.match(name, getterSetterPattern);
075 if (match != null) {
076 Class<?> returnType = method.getReturnType();
077 String fieldName = StringUtils.uncapitalize(match[2]);
078 boolean isGetter = !match[1].equals("set");
079 if (isGetter) {
080 if (nParams == 0) {
081 GetterAndSetterInfo getterAndSetter = getOrCreatePair(fieldName);
082 if (getterAndSetter.getter != null) {
083 if (getterAndSetter.getter.getReturnType().isAssignableFrom(returnType)) {
084 // refinement
085 getterAndSetter.getter = method;
086 }
087 } else {
088 getterAndSetter.getter = method;
089 }
090
091 if (!getterAndSetter.isConsistent())
092 getterAndSetter.setter = null;
093
094 }
095 //assertNull("Already found getter " + getterAndSetter.getter, getterAndSetter.getter);
096 //getterAndSetter.setFirst(method);
097 } else if (nParams == 1) {
098 GetterAndSetterInfo getterAndSetter = getOrCreatePair(fieldName);
099 //assertNull("Already found setter " + getterAndSetter.setter, getterAndSetter.setter);
100 //assert getterAndSetter.setter == null;
101 getterAndSetter.setter = method;
102 if (!getterAndSetter.isConsistent())
103 getterAndSetter.setter = null;
104 }
105 }
106 }
107 /*
108 for (Map.Entry<String, GetterAndSetterInfo> e : gettersAndSetters.entrySet()) {
109 if (e.getValue().setter == null)
110 continue;
111 try {
112 e.getValue().field = fieldGetter == null ? type.getField(e.getKey()) : fieldGetter.getField(type, e.getKey());
113 } catch (Exception ex) {
114 assertTrue("Failed to find field '" + e.getKey() + "' in " + type.getName(), false);
115 }
116 }*/
117 /*for (Field field : type.getFields()) {
118 GetterAndSetterInfo info = gettersAndSetters.get(field.getName());
119 if (info == null)
120 continue;
121 info.field = field;
122 }*/
123 }
124 final FieldGetter fieldGetter;
125 public interface FieldGetter {
126 public Field getField(Class<?> c, String name) throws SecurityException, NoSuchFieldException;
127 }
128 public Set<String> getFieldNames() {
129 return gettersAndSetters.keySet();
130 }
131 public Method getGetter(String fieldName) {
132 GetterAndSetterInfo pair = gettersAndSetters.get(fieldName);
133 return pair == null ? null : pair.getter;
134 }
135 public Method getSetter(String fieldName) {
136 GetterAndSetterInfo pair = gettersAndSetters.get(fieldName);
137 return pair == null ? null : pair.setter;
138 }
139 public Type getFieldType(String fieldName) {
140 GetterAndSetterInfo pair = gettersAndSetters.get(fieldName);
141 if (pair == null)
142 return null;
143 if (pair.getter != null)
144 return pair.getter.getGenericReturnType();
145 if (pair.setter != null)
146 return pair.setter.getGenericParameterTypes()[0];
147 return null;
148 }
149 public void assertConsistentPair(GetterAndSetterInfo p) {
150 if (p.getter != null && p.setter != null) {
151 Class<?> getType = p.getter.getReturnType(),
152 setType = p.setter.getParameterTypes()[0];
153
154 //assertTrue("Setter argument cannot be given getter result", setType.isAssignableFrom(getType));
155 assert setType.isAssignableFrom(getType);
156 }
157 }
158 protected GetterAndSetterInfo getOrCreatePair(String fieldName) {
159 GetterAndSetterInfo getterAndSetter = gettersAndSetters.get(fieldName);
160 if (getterAndSetter == null)
161 gettersAndSetters.put(fieldName, getterAndSetter = new GetterAndSetterInfo());
162
163 return getterAndSetter;
164 }
165 }