001package org.javasimon.console.reflect; 002 003import org.javasimon.console.SimonTypeFactory; 004 005import java.io.IOException; 006import java.io.InputStream; 007import java.lang.reflect.Method; 008import java.lang.reflect.Modifier; 009import java.util.Collection; 010import java.util.HashMap; 011import java.util.Map; 012import java.util.Properties; 013 014/** 015 * {@link Getter} factory. 016 * Contains a cache Class → Property Name → Getter 017 * 018 * @author gquintana 019 */ 020public class GetterFactory { 021 private static final Map<Class, Map<String, Getter>> GETTER_CACHE = new HashMap<>(); 022 023 /** Test whether method is a getter. */ 024 private static boolean isGetterMethod(Method method) { 025 return !Modifier.isStatic(method.getModifiers()) 026 && (method.getName().startsWith("get") || method.getName().startsWith("is")) 027 && method.getParameterTypes().length == 0; 028 } 029 030 /** Transform method name into property name. */ 031 private static String getPropertyName(Method method) { 032 String propertyName = method.getName(); 033 if (propertyName.startsWith("get")) { 034 propertyName = propertyName.substring(3); 035 } else if (propertyName.startsWith("is")) { 036 propertyName = propertyName.substring(2); 037 } 038 propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1); 039 return propertyName; 040 } 041 042 /** Constrains the content of the SubTypes.properties file. */ 043 private static final Properties subTypeProperties = new Properties(); 044 045 static { 046 try { 047 InputStream inputStream = GetterFactory.class.getResourceAsStream("SubTypes.properties"); 048 subTypeProperties.load(inputStream); 049 } catch (IOException iOException) { 050 iOException.printStackTrace(); 051 } 052 } 053 054 /** 055 * Get subtype for given Class and property. 056 * 057 * @param type Parent class 058 * @param propertyName Property name 059 * @return Sub type name 060 */ 061 private static String getSubType(Class type, String propertyName) { 062 @SuppressWarnings("unchecked") 063 Class normalizedType = SimonTypeFactory.normalizeType(type); 064 if (normalizedType == null) { 065 return null; 066 } else { 067 return subTypeProperties.getProperty(normalizedType.getName() + "." + propertyName); 068 } 069 } 070 071 /** 072 * Extract all getters for given class. 073 * 074 * @param type Class 075 * @return List of getters 076 */ 077 @SuppressWarnings("unchecked") 078 public static Collection<Getter> getGetters(Class type) { 079 return getGettersAsMap(type).values(); 080 } 081 082 /** 083 * Extract all getters for given class. 084 * 085 * @param type Class 086 * @return Map property name → Getter 087 */ 088 private static Map<String, Getter> getGettersAsMap(Class type) { 089 Map<String, Getter> typeGetters = GETTER_CACHE.get(type); 090 if (typeGetters == null) { 091 typeGetters = new HashMap<>(); 092 for (Method method : type.getMethods()) { 093 if (isGetterMethod(method)) { 094 String propertyName = getPropertyName(method); 095 Class propertyType = method.getReturnType(); 096 //noinspection unchecked 097 typeGetters.put(propertyName, new Getter(propertyName, propertyType, getSubType(type, propertyName), method)); 098 } 099 } 100 GETTER_CACHE.put(type, typeGetters); 101 } 102 return typeGetters; 103 } 104 105 /** 106 * Search getter for given class and property name. 107 * 108 * @param type Class 109 * @param name Property name 110 * @return Getter or null if not found 111 */ 112 @SuppressWarnings("unchecked") 113 public static Getter getGetter(Class type, String name) { 114 return getGettersAsMap(type).get(name); 115 } 116}