package com.alibaba.excel.util; import java.lang.ref.SoftReference; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.event.Handler; import com.alibaba.excel.exception.ExcelCommonException; import com.alibaba.excel.metadata.BaseRowModel; import com.alibaba.excel.metadata.Holder; import com.alibaba.excel.write.handler.WriteHandler; import com.alibaba.excel.write.metadata.holder.WriteHolder; /** * Class utils * * @author Jiaju Zhuang **/ public class ClassUtils { private static final Map> FIELD_CACHE = new ConcurrentHashMap>(); public static void declaredFields(Class clazz, Map sortedAllFiledMap, Map indexFiledMap, Map ignoreMap, Boolean convertAllFiled, Boolean needIgnore, Holder holder) { FieldCache fieldCache = getFieldCache(clazz, convertAllFiled); if (fieldCache == null) { return; } if (ignoreMap != null) { ignoreMap.putAll(fieldCache.getIgnoreMap()); } Map tempIndexFildMap = indexFiledMap; if (tempIndexFildMap == null) { tempIndexFildMap = new TreeMap(); } tempIndexFildMap.putAll(fieldCache.getIndexFiledMap()); if (!needIgnore) { sortedAllFiledMap.putAll(fieldCache.getSortedAllFiledMap()); return; } int index = 0; for (Map.Entry entry : fieldCache.getSortedAllFiledMap().entrySet()) { Field field = entry.getValue(); if (((WriteHolder) holder).ignore(entry.getValue().getName(), entry.getKey())) { if (ignoreMap != null) { ignoreMap.put(field.getName(), field); } while (tempIndexFildMap.containsKey(index)) { tempIndexFildMap.remove(index); index++; } } else { sortedAllFiledMap.put(index, field); index++; } } } public static void declaredFields(Class clazz, Map sortedAllFiledMap, Boolean convertAllFiled, Boolean needIgnore, WriteHolder writeHolder) { declaredFields(clazz, sortedAllFiledMap, null, null, convertAllFiled, needIgnore, writeHolder); } private static FieldCache getFieldCache(Class clazz, Boolean convertAllFiled) { if (clazz == null) { return null; } SoftReference fieldCacheSoftReference = FIELD_CACHE.get(clazz); if (fieldCacheSoftReference != null && fieldCacheSoftReference.get() != null) { return fieldCacheSoftReference.get(); } synchronized (clazz) { fieldCacheSoftReference = FIELD_CACHE.get(clazz); if (fieldCacheSoftReference != null && fieldCacheSoftReference.get() != null) { return fieldCacheSoftReference.get(); } declaredFields(clazz, convertAllFiled); } return FIELD_CACHE.get(clazz).get(); } private static void declaredFields(Class clazz, Boolean convertAllFiled) { List tempFieldList = new ArrayList(); Class tempClass = clazz; // When the parent class is null, it indicates that the parent class (Object class) has reached the top // level. while (tempClass != null && tempClass != BaseRowModel.class) { Collections.addAll(tempFieldList, tempClass.getDeclaredFields()); // Get the parent class and give it to yourself tempClass = tempClass.getSuperclass(); } // Screening of field Map> orderFiledMap = new TreeMap>(); Map indexFiledMap = new TreeMap(); Map ignoreMap = new HashMap(16); ExcelIgnoreUnannotated excelIgnoreUnannotated = (ExcelIgnoreUnannotated) clazz.getAnnotation(ExcelIgnoreUnannotated.class); for (Field field : tempFieldList) { declaredOneField(field, orderFiledMap, indexFiledMap, ignoreMap, excelIgnoreUnannotated, convertAllFiled); } FIELD_CACHE.put(clazz, new SoftReference( new FieldCache(buildSortedAllFiledMap(orderFiledMap, indexFiledMap), indexFiledMap, ignoreMap))); } private static Map buildSortedAllFiledMap(Map> orderFiledMap, Map indexFiledMap) { Map sortedAllFiledMap = new HashMap( (orderFiledMap.size() + indexFiledMap.size()) * 4 / 3 + 1); Map tempIndexFiledMap = new HashMap(indexFiledMap); int index = 0; for (List fieldList : orderFiledMap.values()) { for (Field field : fieldList) { while (tempIndexFiledMap.containsKey(index)) { sortedAllFiledMap.put(index, tempIndexFiledMap.get(index)); tempIndexFiledMap.remove(index); index++; } sortedAllFiledMap.put(index, field); index++; } } sortedAllFiledMap.putAll(tempIndexFiledMap); return sortedAllFiledMap; } private static void declaredOneField(Field field, Map> orderFiledMap, Map indexFiledMap, Map ignoreMap, ExcelIgnoreUnannotated excelIgnoreUnannotated, Boolean convertAllFiled) { ExcelIgnore excelIgnore = field.getAnnotation(ExcelIgnore.class); if (excelIgnore != null) { ignoreMap.put(field.getName(), field); return; } ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); boolean noExcelProperty = excelProperty == null && ((convertAllFiled != null && !convertAllFiled) || excelIgnoreUnannotated != null); if (noExcelProperty) { ignoreMap.put(field.getName(), field); return; } boolean isStaticFinalOrTransient = (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers())) || Modifier.isTransient(field.getModifiers()); if (excelProperty == null && isStaticFinalOrTransient) { ignoreMap.put(field.getName(), field); return; } if (excelProperty != null && excelProperty.index() >= 0) { if (indexFiledMap.containsKey(excelProperty.index())) { throw new ExcelCommonException("The index of '" + indexFiledMap.get(excelProperty.index()).getName() + "' and '" + field.getName() + "' must be inconsistent"); } indexFiledMap.put(excelProperty.index(), field); return; } int order = Integer.MAX_VALUE; if (excelProperty != null) { order = excelProperty.order(); } List orderFiledList = orderFiledMap.get(order); if (orderFiledList == null) { orderFiledList = new ArrayList(); orderFiledMap.put(order, orderFiledList); } orderFiledList.add(field); } private static class FieldCache { private Map sortedAllFiledMap; private Map indexFiledMap; private Map ignoreMap; public FieldCache(Map sortedAllFiledMap, Map indexFiledMap, Map ignoreMap) { this.sortedAllFiledMap = sortedAllFiledMap; this.indexFiledMap = indexFiledMap; this.ignoreMap = ignoreMap; } public Map getSortedAllFiledMap() { return sortedAllFiledMap; } public Map getIndexFiledMap() { return indexFiledMap; } public Map getIgnoreMap() { return ignoreMap; } } }