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 }