/* * Copyright (c) www.bugull.com * * 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 net.tooan.ynpay.third.mongodb.cache; import net.tooan.ynpay.third.jfinal.log.Logger; import net.tooan.ynpay.third.mongodb.annotations.*; import net.tooan.ynpay.third.mongodb.exception.FieldException; import net.tooan.ynpay.third.mongodb.exception.IdException; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** * Cache(Map) contains entity classes' fields, for performance purporse. * * @author Frank Wen(xbwen@hotmail.com) */ public class FieldsCache { private final static Logger logger = Logger.getLogger(FieldsCache.class); private static FieldsCache instance = new FieldsCache(); private final ConcurrentMap<String, Field[]> cache = new ConcurrentHashMap<String, Field[]>(); private FieldsCache() { } public static FieldsCache getInstance() { return instance; } /** * Get all declared and inherited field * * @param clazz * @return */ private Field[] getAllFields(Class<?> clazz) { List<Field> allFields = new ArrayList<Field>(); allFields.addAll(filterFields(clazz.getDeclaredFields())); Class parent = clazz.getSuperclass(); while ((parent != null) && (parent != Object.class)) { allFields.addAll(filterFields(parent.getDeclaredFields())); parent = parent.getSuperclass(); } return allFields.toArray(new Field[allFields.size()]); } /** * Filter the static filed, and set all the filed to alccessibe=true * * @param fields * @return */ private List<Field> filterFields(Field[] fields) { List<Field> result = new ArrayList<Field>(); for (Field field : fields) { if (!Modifier.isStatic(field.getModifiers())) { field.setAccessible(true); result.add(field); } } return result; } public Field[] get(Class<?> clazz) { String name = clazz.getName(); Field[] fields = cache.get(name); if (fields != null) { return fields; } fields = getAllFields(clazz); Field[] temp = cache.putIfAbsent(name, fields); if (temp != null) { return temp; } else { return fields; } } /** * Get the field with @Id on it. * * @param clazz * @return */ public Field getIdField(Class<?> clazz) throws IdException { Field result = null; Field[] fields = get(clazz); for (Field f : fields) { if (f.getAnnotation(Id.class) != null) { result = f; break; } } if (result == null) { throw new IdException(clazz.getName() + " does not contain @Id field."); } return result; } /** * Get the field's name with @Id on it. In natural case, it returns "id". * * @param clazz * @return */ public String getIdFieldName(Class<?> clazz) { String name = null; Field f = null; try { f = this.getIdField(clazz); } catch (IdException ex) { logger.error(ex.getMessage(), ex); } if (f != null) { name = f.getName(); } return name; } /** * Get the field by field name. * * @param clazz * @param fieldName * @return * @throws FieldException */ public Field getField(Class<?> clazz, String fieldName) throws FieldException { Field field = null; Field[] fields = get(clazz); for (Field f : fields) { if (f.getName().equals(fieldName)) { field = f; break; } } if (field == null) { for (Field f : fields) { Property property = f.getAnnotation(Property.class); if (property != null && property.name().equals(fieldName)) { field = f; break; } Embed embed = f.getAnnotation(Embed.class); if (embed != null && embed.name().equals(fieldName)) { field = f; break; } EmbedList el = f.getAnnotation(EmbedList.class); if (el != null && el.name().equals(fieldName)) { field = f; break; } Ref ref = f.getAnnotation(Ref.class); if (ref != null && ref.name().equals(fieldName)) { field = f; break; } RefList rl = f.getAnnotation((RefList.class)); if (rl != null && rl.name().equals(fieldName)) { field = f; break; } } } if (field == null) { throw new FieldException("Field '" + fieldName + "' does not exists!"); } return field; } /** * check if the field is annotated by @EmbedList * * @param clazz * @param fieldName * @return */ public boolean isEmbedListField(Class<?> clazz, String fieldName) { boolean result = false; Field[] fields = get(clazz); for (Field f : fields) { if (f.getName().equals(fieldName) && f.getAnnotation(EmbedList.class) != null) { result = true; break; } } return result; } }