Java tutorial
/* * Copyright 2012 Juan Alberto Lpez Cavallotti * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jdto.impl; import java.lang.reflect.*; import java.util.HashMap; import org.apache.commons.lang.StringUtils; /** * Utility class for extracting properties by matching fields and getter methods. <br /> * THIS IS NOT PART OF JDTO PUBLIC API AND REGULAR USERS SHOULD NOT RELY ON THIS CLASS. <br /> * IT IS MADE PUBLIC JUST FOR PACKAGE ORGANISATION REASONS * @author Juan Alberto Lopez Cavallotti */ class BeanPropertyUtils { /** * Get the type parameter out of a generic type. * @param genericType * @return the type parameter of Object.class */ static Class getGenericTypeParameter(Type genericType) { ParameterizedType fieldParamType = null; if (genericType instanceof ParameterizedType) { fieldParamType = (ParameterizedType) genericType; } if (fieldParamType == null) { return Object.class; } Class typeParameter = (Class) fieldParamType.getActualTypeArguments()[0]; return typeParameter; } /** * Try to find a getter method for the given property on the target class * or any of it's parents excluding the object class. This method will * try to traverse recursively all of the methods. This may not be the most * efficient way to find a getter method, but is included to reduce the * amount of dependencies this framework has with third party libraries. * @param property * @param targetClass * @return the expected method or null. */ static Method findGetterMethod(String property, Class targetClass) { //we're not accepting the object class if (targetClass == Object.class) { return null; } //this is the method list Method[] methods = targetClass.getDeclaredMethods(); for (Method method : methods) { if (!isGetterMethod(method)) { continue; } //get the method name. String methodName = convertToPropertyName(method); //compare it with the property if (property.equals(methodName)) { //we got what we wanted. return method; } } return findGetterMethod(property, targetClass.getSuperclass()); } /** * Find a setter method out of a property name. * @param property * @param targetClass * @return The setter method or null. */ static Method findSetterMethod(String property, Class targetClass) { //we're not accepting the object class if (targetClass == Object.class) { return null; } //this is the method list Method[] methods = targetClass.getDeclaredMethods(); for (Method method : methods) { if (!isSetterMethod(method)) { continue; } //get the method name. String methodName = convertToPropertyName(method); //compare it with the property if (property.equals(methodName)) { //we got what we wanted. return method; } } return findSetterMethod(property, targetClass.getSuperclass()); } /** * Makes discovery of all of the class methods by its getters. <br /> * This method will recurse into the inheritance hierarchy and will stop * on the Object class, finding appropiate getter methods. * @param cls the class to ve traversed * @return */ static HashMap<String, Method> discoverPropertiesByGetters(Class cls) { HashMap<String, Method> methods = new HashMap<String, Method>(); //declare a buffer Class currentClass = cls; //loop to find while (currentClass != Object.class) { for (Method method : currentClass.getDeclaredMethods()) { if (isGetterMethod(method)) { String propertyName = convertToPropertyName(method); methods.put(propertyName, method); } } currentClass = currentClass.getSuperclass(); } return methods; } static boolean isSetterMethod(Method method) { return isAccessorMethod(method, 1, false, "set"); } /** * Check if a method is an getter accessor or not. The checks are not * comprehensive, for example any non-boolean method could start with "is" * and be taken in account, but there should be no problem with that. * @param method * @return */ static boolean isGetterMethod(Method method) { return isAccessorMethod(method, 0, true, "get", "is"); } /** * Determine wether a method is accessor or not, by looking at some properties. * @param method * @param maxParams * @param hasReturnType * @param prefixes * @return */ private static boolean isAccessorMethod(Method method, int maxParams, boolean hasReturnType, String... prefixes) { //first of all, we only want public methods. if (!Modifier.isPublic(method.getModifiers())) { return false; } //check if the method should return something or not. if (hasReturnType) { if (method.getReturnType() == Void.TYPE) { return false; } } //check the method parameter length int parameterAmount = method.getParameterTypes().length; if (parameterAmount > maxParams) { return false; } //check the naming conventions String methodName = method.getName(); if (!org.jdto.util.StringUtils.startsWithAny(methodName, prefixes)) { return false; } //well everything has succeeded, then is an accessor! return true; } /** * Remove the accessor prefix from name and the bean capitalization. * This can be used by getters and setters. * @param method * @return */ private static String convertToPropertyName(Method method) { String methodName = method.getName(); if (StringUtils.startsWith(methodName, "set")) { methodName = StringUtils.removeStart(methodName, "set"); } else if (StringUtils.startsWith(methodName, "is")) { methodName = StringUtils.removeStart(methodName, "is"); } else if (StringUtils.startsWith(methodName, "get")) { methodName = StringUtils.removeStart(methodName, "get"); } //remove the first capital return StringUtils.uncapitalize(methodName); } /** * Read safely a field from a class. This Method tries to find a field by * it's name and silently return null if it is not present. <br /> * Sadly there is not beautiful way of doing this, but we can safely ignore * annotations if no field is found, blame the creators of the reflection * API for this. * @param sourceClass * @param fieldName * @return */ static Field readSafeField(Class sourceClass, String fieldName) { Class classToInspect = sourceClass; //go through the inheritance hierarchy while (classToInspect != Object.class) { try { return classToInspect.getDeclaredField(fieldName); } catch (NoSuchFieldException ex) { classToInspect = classToInspect.getSuperclass(); continue; } } return null; } /** * Find the type of the argument of a setter method. If the method could not * be found, then return null. * @param sourceClass the class to inspect. * @param fieldName the name of the setter we are looking for. * @return the type of the argument or null if not found. */ static Class findMutatorArumentType(Class sourceClass, String fieldName) { Method setter = findSetterMethod(fieldName, sourceClass); if (setter == null) { return null; } Class[] types = setter.getParameterTypes(); return types[0]; } }