|
|
@ -36,6 +36,7 @@ import com.alibaba.excel.metadata.property.StyleProperty; |
|
|
|
import com.alibaba.excel.write.metadata.holder.WriteHolder; |
|
|
|
import com.alibaba.excel.write.metadata.holder.WriteHolder; |
|
|
|
|
|
|
|
|
|
|
|
import lombok.AllArgsConstructor; |
|
|
|
import lombok.AllArgsConstructor; |
|
|
|
|
|
|
|
import lombok.Data; |
|
|
|
import lombok.EqualsAndHashCode; |
|
|
|
import lombok.EqualsAndHashCode; |
|
|
|
import lombok.Getter; |
|
|
|
import lombok.Getter; |
|
|
|
import lombok.Setter; |
|
|
|
import lombok.Setter; |
|
|
@ -49,7 +50,7 @@ import org.springframework.cglib.beans.BeanMap; |
|
|
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
|
|
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
|
|
|
* (the "License"); you may not use this file except in compliance with |
|
|
|
* (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
|
|
|
|
* the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
* |
|
|
|
* <p> |
|
|
|
* Unless required by applicable law or agreed to in writing, software |
|
|
|
* Unless required by applicable law or agreed to in writing, software |
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
|
@ -63,11 +64,11 @@ public class ClassUtils { |
|
|
|
/** |
|
|
|
/** |
|
|
|
* memory cache |
|
|
|
* memory cache |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static final ConcurrentHashMap<Class<?>, FieldCache> FIELD_CACHE = new ConcurrentHashMap<>(); |
|
|
|
public static final Map<FieldCacheKey, FieldCache> FIELD_CACHE = new ConcurrentHashMap<>(); |
|
|
|
/** |
|
|
|
/** |
|
|
|
* thread local cahe |
|
|
|
* thread local cache |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private static final ThreadLocal<Map<Class<?>, FieldCache>> FIELD_THREAD_LOCAL = new ThreadLocal<>(); |
|
|
|
private static final ThreadLocal<Map<FieldCacheKey, FieldCache>> FIELD_THREAD_LOCAL = new ThreadLocal<>(); |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* The cache configuration information for each of the class
|
|
|
|
* The cache configuration information for each of the class
|
|
|
@ -102,7 +103,8 @@ public class ClassUtils { |
|
|
|
* @return |
|
|
|
* @return |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static ExcelContentProperty declaredExcelContentProperty(Map<?, ?> dataMap, Class<?> headClazz, |
|
|
|
public static ExcelContentProperty declaredExcelContentProperty(Map<?, ?> dataMap, Class<?> headClazz, |
|
|
|
String fieldName, ConfigurationHolder configurationHolder) { |
|
|
|
String fieldName, |
|
|
|
|
|
|
|
ConfigurationHolder configurationHolder) { |
|
|
|
Class<?> clazz = null; |
|
|
|
Class<?> clazz = null; |
|
|
|
if (dataMap instanceof BeanMap) { |
|
|
|
if (dataMap instanceof BeanMap) { |
|
|
|
Object bean = ((BeanMap)dataMap).getBean(); |
|
|
|
Object bean = ((BeanMap)dataMap).getBean(); |
|
|
@ -137,7 +139,8 @@ public class ClassUtils { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static ExcelContentProperty doGetExcelContentProperty(Class<?> clazz, Class<?> headClass, |
|
|
|
private static ExcelContentProperty doGetExcelContentProperty(Class<?> clazz, Class<?> headClass, |
|
|
|
String fieldName, ConfigurationHolder configurationHolder) { |
|
|
|
String fieldName, |
|
|
|
|
|
|
|
ConfigurationHolder configurationHolder) { |
|
|
|
ExcelContentProperty excelContentProperty = Optional.ofNullable( |
|
|
|
ExcelContentProperty excelContentProperty = Optional.ofNullable( |
|
|
|
declaredFieldContentMap(clazz, configurationHolder)) |
|
|
|
declaredFieldContentMap(clazz, configurationHolder)) |
|
|
|
.map(map -> map.get(fieldName)) |
|
|
|
.map(map -> map.get(fieldName)) |
|
|
@ -277,16 +280,16 @@ public class ClassUtils { |
|
|
|
public static FieldCache declaredFields(Class<?> clazz, ConfigurationHolder configurationHolder) { |
|
|
|
public static FieldCache declaredFields(Class<?> clazz, ConfigurationHolder configurationHolder) { |
|
|
|
switch (configurationHolder.globalConfiguration().getFiledCacheLocation()) { |
|
|
|
switch (configurationHolder.globalConfiguration().getFiledCacheLocation()) { |
|
|
|
case THREAD_LOCAL: |
|
|
|
case THREAD_LOCAL: |
|
|
|
Map<Class<?>, FieldCache> fieldCacheMap = FIELD_THREAD_LOCAL.get(); |
|
|
|
Map<FieldCacheKey, FieldCache> fieldCacheMap = FIELD_THREAD_LOCAL.get(); |
|
|
|
if (fieldCacheMap == null) { |
|
|
|
if (fieldCacheMap == null) { |
|
|
|
fieldCacheMap = MapUtils.newHashMap(); |
|
|
|
fieldCacheMap = MapUtils.newHashMap(); |
|
|
|
FIELD_THREAD_LOCAL.set(fieldCacheMap); |
|
|
|
FIELD_THREAD_LOCAL.set(fieldCacheMap); |
|
|
|
} |
|
|
|
} |
|
|
|
return fieldCacheMap.computeIfAbsent(clazz, key -> { |
|
|
|
return fieldCacheMap.computeIfAbsent(new FieldCacheKey(clazz, configurationHolder), key -> { |
|
|
|
return doDeclaredFields(clazz, configurationHolder); |
|
|
|
return doDeclaredFields(clazz, configurationHolder); |
|
|
|
}); |
|
|
|
}); |
|
|
|
case MEMORY: |
|
|
|
case MEMORY: |
|
|
|
return FIELD_CACHE.computeIfAbsent(clazz, key -> { |
|
|
|
return FIELD_CACHE.computeIfAbsent(new FieldCacheKey(clazz, configurationHolder), key -> { |
|
|
|
return doDeclaredFields(clazz, configurationHolder); |
|
|
|
return doDeclaredFields(clazz, configurationHolder); |
|
|
|
}); |
|
|
|
}); |
|
|
|
case NONE: |
|
|
|
case NONE: |
|
|
@ -333,7 +336,7 @@ public class ClassUtils { |
|
|
|
return fieldCache; |
|
|
|
return fieldCache; |
|
|
|
} |
|
|
|
} |
|
|
|
// ignore filed
|
|
|
|
// ignore filed
|
|
|
|
Map<Integer, FieldWrapper> tempSortedFieldMapp = MapUtils.newHashMap(); |
|
|
|
Map<Integer, FieldWrapper> tempSortedFieldMap = MapUtils.newHashMap(); |
|
|
|
int index = 0; |
|
|
|
int index = 0; |
|
|
|
for (Map.Entry<Integer, FieldWrapper> entry : sortedFieldMap.entrySet()) { |
|
|
|
for (Map.Entry<Integer, FieldWrapper> entry : sortedFieldMap.entrySet()) { |
|
|
|
Integer key = entry.getKey(); |
|
|
|
Integer key = entry.getKey(); |
|
|
@ -346,18 +349,18 @@ public class ClassUtils { |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// Mandatory sorted fields
|
|
|
|
// Mandatory sorted fields
|
|
|
|
if (indexFieldMap.containsKey(key)) { |
|
|
|
if (indexFieldMap.containsKey(key)) { |
|
|
|
tempSortedFieldMapp.put(key, field); |
|
|
|
tempSortedFieldMap.put(key, field); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// Need to reorder automatically
|
|
|
|
// Need to reorder automatically
|
|
|
|
// Check whether the current key is already in use
|
|
|
|
// Check whether the current key is already in use
|
|
|
|
while (tempSortedFieldMapp.containsKey(index)) { |
|
|
|
while (tempSortedFieldMap.containsKey(index)) { |
|
|
|
index++; |
|
|
|
index++; |
|
|
|
} |
|
|
|
} |
|
|
|
tempSortedFieldMapp.put(index++, field); |
|
|
|
tempSortedFieldMap.put(index++, field); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
fieldCache.setSortedFieldMap(tempSortedFieldMapp); |
|
|
|
fieldCache.setSortedFieldMap(tempSortedFieldMap); |
|
|
|
|
|
|
|
|
|
|
|
// resort field
|
|
|
|
// resort field
|
|
|
|
resortField(writeHolder, fieldCache); |
|
|
|
resortField(writeHolder, fieldCache); |
|
|
@ -406,8 +409,8 @@ public class ClassUtils { |
|
|
|
// Index sorted map
|
|
|
|
// Index sorted map
|
|
|
|
Map<Integer, Integer> filedIndexMap = MapUtils.newHashMap(); |
|
|
|
Map<Integer, Integer> filedIndexMap = MapUtils.newHashMap(); |
|
|
|
int fieldIndex = 0; |
|
|
|
int fieldIndex = 0; |
|
|
|
for (Integer includeColumnIndexe : includeColumnIndexes) { |
|
|
|
for (Integer includeColumnIndex : includeColumnIndexes) { |
|
|
|
filedIndexMap.put(includeColumnIndexe, fieldIndex++); |
|
|
|
filedIndexMap.put(includeColumnIndex, fieldIndex++); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// rebuild sortedFieldMap
|
|
|
|
// rebuild sortedFieldMap
|
|
|
@ -551,6 +554,24 @@ public class ClassUtils { |
|
|
|
private String fieldName; |
|
|
|
private String fieldName; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Data |
|
|
|
|
|
|
|
public static class FieldCacheKey { |
|
|
|
|
|
|
|
private Class<?> clazz; |
|
|
|
|
|
|
|
private Collection<String> excludeColumnFieldNames; |
|
|
|
|
|
|
|
private Collection<Integer> excludeColumnIndexes; |
|
|
|
|
|
|
|
private Collection<String> includeColumnFieldNames; |
|
|
|
|
|
|
|
private Collection<Integer> includeColumnIndexes; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FieldCacheKey(Class<?> clazz, ConfigurationHolder configurationHolder) { |
|
|
|
|
|
|
|
this.clazz = clazz; |
|
|
|
|
|
|
|
WriteHolder writeHolder = (WriteHolder)configurationHolder; |
|
|
|
|
|
|
|
this.excludeColumnFieldNames = writeHolder.excludeColumnFieldNames(); |
|
|
|
|
|
|
|
this.excludeColumnIndexes = writeHolder.excludeColumnIndexes(); |
|
|
|
|
|
|
|
this.includeColumnFieldNames = writeHolder.includeColumnFieldNames(); |
|
|
|
|
|
|
|
this.includeColumnIndexes = writeHolder.includeColumnIndexes(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static void removeThreadLocalCache() { |
|
|
|
public static void removeThreadLocalCache() { |
|
|
|
FIELD_THREAD_LOCAL.remove(); |
|
|
|
FIELD_THREAD_LOCAL.remove(); |
|
|
|
CLASS_CONTENT_THREAD_LOCAL.remove(); |
|
|
|
CLASS_CONTENT_THREAD_LOCAL.remove(); |
|
|
|