Java tutorial
/* * Copyright (c) 2013 @iSQWEN. All rights reserved. * * 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.faster.opm; import org.faster.opm.annotation.ExcludeProperty; import org.faster.opm.annotation.Index; import org.faster.opm.annotation.Property; import org.faster.opm.annotation.PropertyStrategy; import org.faster.opm.annotation.Resource; import org.faster.opm.annotation.ResourceID; import org.faster.util.DateTimes; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import static org.apache.commons.lang3.StringUtils.isBlank; /** * ? * * @author sqwen * @date 2012-4-22 */ public class PropertyHelper { private PropertyHelper() { } // ? private final static Set<Class<?>> parsedClasses = new HashSet<Class<?>>(); // ?ID private final static Map<Class<?>, Method> resourceIdMethodMap = new ConcurrentHashMap<Class<?>, Method>(); // ?ID private final static Map<Class<?>, Field> resourceIdFieldMap = new ConcurrentHashMap<Class<?>, Field>(); // ? private final static Map<Class<?>, List<Method>> propertyMethodsMap = new ConcurrentHashMap<Class<?>, List<Method>>(); // ? private final static Map<Class<?>, List<Method>> indexMethodsMap = new ConcurrentHashMap<Class<?>, List<Method>>(); // ? private final static Map<Class<?>, List<Field>> propertyFieldsMap = new ConcurrentHashMap<Class<?>, List<Field>>(); // ? private final static Map<Class<?>, List<Field>> indexFieldsMap = new ConcurrentHashMap<Class<?>, List<Field>>(); // // key? // value??? private final static Map<String, List<String>> uniqueIndexMap = new HashMap<String, List<String>>(); public static final boolean isResourceIDMethod(Method method) { return method.isAnnotationPresent(ResourceID.class); } public static final boolean isResourceIDField(Field field) { return field.isAnnotationPresent(ResourceID.class); } public static final boolean isPropertyMethod(Resource resource, Method method) { if (method.isAnnotationPresent(Property.class)) { return true; } if (resource.defaultPropertyStrategy() == PropertyStrategy.EXCLUDE) { return false; } if (Modifier.isStatic(method.getModifiers())) { return false; } return !method.isAnnotationPresent(ExcludeProperty.class); } // public static final boolean isIndexMethod(Resource resource, Method method) { // return method.isAnnotationPresent(Index.class); // } // // public static final boolean isUniqueIndexMethod(Resource resource, Method // method) { // Index index = method.getAnnotation(Index.class); // return index != null && index.unique(); // } public static final boolean isPropertyField(Resource resource, Field field) { if (field.isAnnotationPresent(org.faster.opm.annotation.Property.class)) { return true; } if (resource.defaultPropertyStrategy() == PropertyStrategy.EXCLUDE) { return false; } if (Modifier.isStatic(field.getModifiers())) { return false; } return !field.isAnnotationPresent(ExcludeProperty.class); } // public static final boolean isIndexField(Resource resource, Field field) { // return field.isAnnotationPresent(Index.class); // } public static final Method getResourceIDMethod(Class<?> clazz) { Method m = resourceIdMethodMap.get(clazz); if (m == null && !parsedClasses.contains(clazz)) { synchronized (clazz) { if (!parsedClasses.contains(clazz)) { parseClass(clazz); m = resourceIdMethodMap.get(clazz); } } } return m; } public static final Field getResourceIDField(Class<?> clazz) { Field f = resourceIdFieldMap.get(clazz); if (f == null && !parsedClasses.contains(clazz)) { synchronized (clazz) { if (!parsedClasses.contains(clazz)) { parseClass(clazz); f = resourceIdFieldMap.get(clazz); } } } return f; } public static final List<Method> getPropertyMethods(Class<?> clazz) { List<Method> ret = propertyMethodsMap.get(clazz); if (ret == null && !parsedClasses.contains(clazz)) { synchronized (clazz) { if (!parsedClasses.contains(clazz)) { parseClass(clazz); ret = propertyMethodsMap.get(clazz); } } } return ret; } public static final List<Field> getPropertyFields(Class<?> clazz) { List<Field> ret = propertyFieldsMap.get(clazz); if (ret == null && !parsedClasses.contains(clazz)) { synchronized (clazz) { if (!parsedClasses.contains(clazz)) { parseClass(clazz); ret = propertyFieldsMap.get(clazz); } } } return ret; } public static final List<Method> getIndexMethods(Class<?> clazz) { List<Method> ret = indexMethodsMap.get(clazz); if (ret == null && !parsedClasses.contains(clazz)) { synchronized (clazz) { if (!parsedClasses.contains(clazz)) { parseClass(clazz); ret = indexMethodsMap.get(clazz); } } } return ret; } public static final List<Field> getIndexFields(Class<?> clazz) { List<Field> ret = indexFieldsMap.get(clazz); if (ret == null && !parsedClasses.contains(clazz)) { synchronized (clazz) { if (!parsedClasses.contains(clazz)) { parseClass(clazz); ret = indexFieldsMap.get(clazz); } } } return ret; } private static final void parseClass(Class<?> clazz) { Resource resource = clazz.getAnnotation(Resource.class); List<Class<?>> classes = new LinkedList<Class<?>>(); Class<?> searchClass = clazz; do { classes.add(0, searchClass); } while ((searchClass = searchClass.getSuperclass()) != null); List<Method> propertyMethods = new LinkedList<Method>(); List<Method> indexMethods = new LinkedList<Method>(); List<String> uniqueIndexes = new LinkedList<String>(); Set<String> propertyMethodNames = new HashSet<String>(); boolean findResourceId = false; for (Class<?> cls : classes) { Method[] methods = cls.getDeclaredMethods(); for (Method method : methods) { method.setAccessible(true); if (!method.getName().startsWith("get")) { continue; } if (method.getName().equals("getClass")) { continue; } if (isResourceIDMethod(method)) { if (findResourceId) { throw new IllegalArgumentException("Find multiple ResourceId annotation, only allow one"); } else { resourceIdMethodMap.put(clazz, method); findResourceId = true; } } if (isPropertyMethod(resource, method)) { // @ResourceId@Property??? propertyMethods.add(method); propertyMethodNames.add(convertGetterMethodName(method.getName())); Index index = method.getAnnotation(Index.class); if (index != null) { indexMethods.add(method); if (index.unique()) { uniqueIndexes.add(getIndexName(index, method)); } } } } } List<Field> propertyFields = new LinkedList<Field>(); List<Field> indexFields = new LinkedList<Field>(); for (Class<?> cls : classes) { Field[] fields = cls.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); if (isResourceIDField(field)) { if (findResourceId) { throw new IllegalArgumentException("Find multiple ResourceId annotation, only allow one"); } else { resourceIdFieldMap.put(clazz, field); findResourceId = true; } } if (propertyMethodNames.contains(field.getName())) { continue; // ?getter@Property } if (isPropertyField(resource, field)) { // @ResourceId@Property??? propertyFields.add(field); Index index = field.getAnnotation(Index.class); if (index != null) { indexFields.add(field); if (index.unique()) { uniqueIndexes.add(getIndexName(index, field)); } } } } } if (!resourceIdMethodMap.containsKey(clazz) && !resourceIdFieldMap.containsKey(clazz)) { throw new IllegalArgumentException("There is no ResourceId annotated."); } parsedClasses.add(clazz); propertyMethodsMap.put(clazz, propertyMethods); indexMethodsMap.put(clazz, indexMethods); propertyFieldsMap.put(clazz, propertyFields); indexFieldsMap.put(clazz, indexFields); String resourceType = ResourceHelper.getResourceType(clazz); uniqueIndexMap.put(resourceType, uniqueIndexes); } public static final String getIndexName(Index index, Method m) { return isBlank(index.name()) ? PropertyHelper.getId(m) : index.name(); } public static final String getIndexName(Index index, Field f) { return isBlank(index.name()) ? PropertyHelper.getId(f) : index.name(); } public static final String getResourceID(Object obj) { Class<?> clazz = obj.getClass(); Method m = getResourceIDMethod(clazz); if (m != null) { return getResourceID(obj, m); } Field f = getResourceIDField(clazz); if (f != null) { return getResourceID(obj, f); } else { throw new IllegalArgumentException("There is no ResourceId annotated."); } } public static final String getResourceID(Object obj, Method m) { Object value; try { value = m.invoke(obj, new Object[0]); if (value != null) { return convertToString(value); } return "<null>"; } catch (Exception e) { throw new OpmException("Can't get resource id from object: " + obj + " by method: " + m.getName(), e); } } public static final String getResourceID(Object obj, Field f) { Object value; try { value = f.get(obj); if (value != null) { return convertToString(value); } return "<null>"; } catch (Exception e) { throw new OpmException("Can't get resource id from object: " + obj + " by field: " + f.getName(), e); } } /** * get?getId -> idgetName -> name * * @param name * ?? * @return ???? */ public static final String convertGetterMethodName(String name) { return new StringBuilder(name.length() - 3).append(Character.toLowerCase(name.charAt(3))) .append(name.substring(4)).toString(); } public static final String getId(Method m) { Property p = m.getAnnotation(Property.class); return p == null || isBlank(p.id()) ? convertGetterMethodName(m.getName()) : p.id(); } public static final String getId(Field f) { Property p = f.getAnnotation(Property.class); return p == null || isBlank(p.id()) ? f.getName() : p.id(); } public static final String getName(Method m) { Property p = m.getAnnotation(Property.class); return p == null || isBlank(p.name()) ? convertGetterMethodName(m.getName()) : p.name(); } public static final String getName(Field f) { Property p = f.getAnnotation(Property.class); return p == null || isBlank(p.name()) ? f.getName() : p.name(); } public static final String getGroup(Method f) { Property p = f.getAnnotation(Property.class); return p == null || isBlank(p.group()) ? null : p.group(); } public static final String getGroup(Field f) { Property p = f.getAnnotation(Property.class); return p == null || isBlank(p.group()) ? null : p.group(); } public static final String getValue(Object obj, Method m) { Object value; try { value = m.invoke(obj, new Object[0]); if (value != null) { return convertToString(value); } Property p = m.getAnnotation(Property.class); return p == null ? null : p.defaultValue(); } catch (Exception e) { throw new OpmException("Can't get value from object: " + obj + " by method: " + m.getName(), e); } } public static final String getValue(Object obj, Field f) { Object value; try { value = f.get(obj); if (value != null) { return convertToString(value); } Property p = f.getAnnotation(Property.class); return p == null ? null : p.defaultValue(); } catch (Exception e) { throw new OpmException("Can't get value from object: " + obj + " by field: " + f.getName(), e); } } protected static final String convertToString(Object value) { if (value instanceof Date) { return DateTimes.formatDateToTimestampString((Date) value); } if (value instanceof Calendar) { return DateTimes.formatDateToTimestampString(((Calendar) value).getTime()); } return String.valueOf(value); } public static final boolean isUniqueIndex(String resourceType, String propertyId) { List<String> list = uniqueIndexMap.get(resourceType); return list == null ? false : list.contains(propertyId); } }