/* Copyright (C) 2006 Christian Schneider * * This file is part of Nomad. * * Nomad is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Nomad is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Nomad; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package net.sf.nmedit.jtheme.reflect; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Map; import net.sf.nmedit.jtheme.annotation.ParameterBinding; public class PropertyDatabase { private PropertyExclusionFilter exclusionFilter; private Map<Class<?>, PropertyAccessGroup> dbMap = new HashMap<Class<?>,PropertyAccessGroup>(100); public PropertyDatabase() { super(); } public PropertyExclusionFilter getExclusionFilter() { return exclusionFilter; } public void setExclusionFilter(PropertyExclusionFilter filter) { if (exclusionFilter != filter) { dbMap.clear(); this.exclusionFilter = filter; } } public PropertyAccessGroup getPropertyAccessGroup(Class<?> target) { PropertyAccessGroup group = dbMap.get(target); if (group == null) { group = getProperties(target); dbMap.put(target, group); } return group; } protected PropertyAccessGroup getProperties(Class<?> target) { Map<String, PropertyAccess> properties = new HashMap<String, PropertyAccess>(100); listProperties(target, properties); return new PropertyAccessGroup(target, properties); } private static final int VALID_MODIFIERS = Modifier.PUBLIC; private static final int INVALID_MODIFIERS = Modifier.ABSTRACT|Modifier.STATIC; protected void listProperties(Class<?> target, Map<String, PropertyAccess> properties) { Method[] methods = target.getMethods(); Map<String,Method> getters = new HashMap<String,Method>(methods.length); Map<String,Method> setters = new HashMap<String,Method>(methods.length); for (int i=0;i<methods.length;i++) { Method m = methods[i]; if ((m.getModifiers() & VALID_MODIFIERS) > 0 && ((m.getModifiers() & INVALID_MODIFIERS) == 0)) { ParameterBinding pbinding = m.getAnnotation(ParameterBinding.class); if (pbinding != null) { if (m.getReturnType() == Void.TYPE && m.getParameterTypes().length==1) { setters.put(pbinding.name(), m); } else if (m.getReturnType() != Void.TYPE && m.getParameterTypes().length == 0) { getters.put(pbinding.name(), m); } } else { String name = m.getName(); if ( name.length()>3 && name.startsWith("set") ) { if ( m.getReturnType() == Void.TYPE && m.getParameterTypes().length==1) { putSafely(setters, extractPropertyName(name, 3), m); } } else if (m.getReturnType() != Void.TYPE && m.getParameterTypes().length==0) { String n = m.getName(); if (name.length()>3 && n.startsWith("has")|n.startsWith("get")) { putSafely(getters, extractPropertyName(name, 3), m); } else if (name.length()>2 && n.startsWith("is")) { putSafely(getters, extractPropertyName(name, 2), m); } } } } } // now find getter/setter pairs for (String property : getters.keySet()) { Method setter = setters.get(property); if (setter != null) { Method getter = getters.get(property); if (setter.getParameterTypes()[0]==getter.getReturnType()) { properties.put(property, new PropertyAccess(property, getter, setter)); } } } } private void putSafely(Map<String, Method> map, String property, Method method) { if (exclusionFilter != null && exclusionFilter.exlusive(property)) return; Method oldMethod = map.get(property); if (oldMethod != null && oldMethod.isAnnotationPresent(ParameterBinding.class)) { return; } map.put(property, method); } private String extractPropertyName(String methodName, int prefixLen) { if (methodName.length() == prefixLen+1) { return Character.toString(Character.toLowerCase(methodName.charAt(prefixLen))); } if (Character.isUpperCase(methodName.charAt(prefixLen+1))) return methodName.substring(prefixLen); else return Character.toLowerCase(methodName.charAt(prefixLen))+methodName.substring(prefixLen+1); } public static final int RETURNTYPE_INVALID = -1; public static final int RETURNTYPE_VOID = 0; public static final int RETURNTYPE_HASRETURNTYPE = 1; public static int getReturnTypeInfo(Method method, Class<?> type) { Class<?> returnType = method.getReturnType(); if (returnType == Void.TYPE) return RETURNTYPE_VOID; else if (returnType == type) return RETURNTYPE_HASRETURNTYPE; else return RETURNTYPE_INVALID; } public static final int PARAMETERLIST_INVALID = -1; public static final int PARAMETERLIST_NOPARAMETER = 0; public static final int PARAMETERLIST_HASPARAMETER = 1; public static int getParameterInfo(Method method, Class<?> type) { Class<?>[] paramTypes = method.getParameterTypes(); if (paramTypes.length == 0) return PARAMETERLIST_NOPARAMETER; else if (paramTypes.length == 1 && paramTypes[0] == type) return PARAMETERLIST_HASPARAMETER; else return PARAMETERLIST_INVALID; } /* // for testing this class public static void main(String[] args) { PropertyDatabase pd = new PropertyDatabase(); PropertyAccessGroup group = pd.getPropertyAccessGroup(TestClass.class); System.out.println(group.getTarget()+":"); for (PropertyAccess pa : group) { System.out.println(pa); } } public static class TestClass { public static int getShouldBeIgnored() { return 0; } public static void getShouldBeIgnored(int inte) { } @ParameterBinding(name="silly") public int getSillyGetterName() { return 0; } @ParameterBinding(name="silly") public void setSillySetterName(int s) { } // this should not overwrite setSillySetterName(int) public void setSilly(int silly) { // } public boolean isPropertyAEnabled() { return false; } public void setPropertyAEnabled(boolean e) { } } */ }