/** Retrieves all {@link Editable} properties of the specified class. */ protected static void createProperties(Class<?> clazz, ArrayList<Property> properties) { // prepend the superclass properties Class<?> sclazz = clazz.getSuperclass(); if (sclazz != null) { Collections.addAll(properties, getProperties(sclazz)); } // find the getters and setters HashMap<String, Method> unpaired = new HashMap<String, Method>(); for (Method method : clazz.getDeclaredMethods()) { if (!method.isAnnotationPresent(Editable.class)) { continue; } String name = method.getName(); boolean getter; if (name.startsWith("set")) { name = name.substring(3); getter = false; } else { if (name.startsWith("get")) { name = name.substring(3); } else if (name.startsWith("is")) { name = name.substring(2); } else { log.warning( "Invalid method name for editable property [class=" + clazz + ", name=" + name + "]."); continue; } getter = true; } Method omethod = unpaired.remove(name); if (omethod != null) { Method gmethod = getter ? method : omethod; Method smethod = getter ? omethod : method; Class<?> rtype = gmethod.getReturnType(); Class<?>[] ptypes = smethod.getParameterTypes(); if (ptypes.length != 1 || ptypes[0] != rtype) { log.warning( "Mismatched types on getter/setter [class=" + clazz + ", getter=" + gmethod + ", setter=" + smethod + "]."); continue; } properties.add(new MethodProperty(gmethod, smethod)); } else { unpaired.put(name, method); } } if (!unpaired.isEmpty()) { log.warning( "Found unmatched getters/setters [class=" + clazz + ", methods=" + unpaired.values() + "]."); } // add all editable fields for (Field field : clazz.getDeclaredFields()) { if (field.isAnnotationPresent(Editable.class)) { properties.add(new FieldProperty(field)); } } }