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    }