Merge pull request #117 from awakeyoyoyo/main

perf[orm]: Rewrite collection declaration type check & Support deseri…
This commit is contained in:
godotg
2024-06-24 16:13:55 +08:00
committed by GitHub
5 changed files with 93 additions and 23 deletions
@@ -17,6 +17,7 @@ import org.bson.BsonWriter;
import org.bson.codecs.Codec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
import org.bson.codecs.configuration.CodecConfigurationException;
import java.util.HashMap;
import java.util.Map;
@@ -61,7 +62,7 @@ public class MapCodec<K, V> implements Codec<Map<K, V>> {
@Override
public Map<K, V> decode(BsonReader reader, DecoderContext context) {
var map = new HashMap<K, V>();
var map = getInstance();
reader.readStartDocument();
while (BsonType.END_OF_DOCUMENT != reader.readBsonType()) {
K key = keyDecodeFunction.apply(reader.readName());
@@ -81,6 +82,15 @@ public class MapCodec<K, V> implements Codec<Map<K, V>> {
public Class<Map<K, V>> getEncoderClass() {
return encoderClass;
}
private Map<K, V> getInstance() {
if (encoderClass.isInterface()) {
return new HashMap<>();
}
try {
return encoderClass.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new CodecConfigurationException(e.getMessage(), e);
}
}
}
@@ -40,6 +40,8 @@ import org.bson.Document;
import org.bson.codecs.configuration.CodecRegistries;
import org.bson.codecs.pojo.PojoCodecProvider;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
@@ -61,7 +63,7 @@ import java.util.concurrent.TimeUnit;
* @author godotg
*/
public class OrmManager implements IOrmManager {
private static final Logger logger = LoggerFactory.getLogger(OrmManager.class);
private OrmConfig ormConfig;
private MongoClient mongoClient;
@@ -479,6 +481,7 @@ public class OrmManager implements IOrmManager {
}
var filedList = ReflectionUtils.notStaticAndTransientFields(clazz);
boolean concurrentSecurityFlag=true;
for (var field : filedList) {
// entity必须包含属性的get和set方法
@@ -495,9 +498,10 @@ public class OrmManager implements IOrmManager {
// ORM的数组类型只支持byte[]
AssertionUtils.isTrue(arrayClazz == byte.class, "The array type of ORM[class:{}] only supports byte[]", clazz.getCanonicalName());
} else if (Set.class.isAssignableFrom(fieldType)) {
// 必须是Set接口类型
AssertionUtils.isTrue(fieldType.equals(Set.class), "[class:{}] type declaration is incorrect, and it must be of the Set interface type", clazz.getCanonicalName());
// 是一个Set
if (fieldType.equals(Set.class)){
concurrentSecurityFlag = false;
}
var type = field.getGenericType();
// field必须泛型类
AssertionUtils.isTrue(type instanceof ParameterizedType, "[class:{}] type declaration is incorrect, not a generic class[field:{}]", clazz.getCanonicalName(), field.getName());
@@ -508,8 +512,9 @@ public class OrmManager implements IOrmManager {
checkSubEntity(clazz, types[0]);
} else if (List.class.isAssignableFrom(fieldType)) {
// 是一个List
AssertionUtils.isTrue(fieldType.equals(List.class), "[class:{}] type declaration is incorrect, and it must be of the List interface type", clazz.getCanonicalName());
if (fieldType.equals(List.class)){
concurrentSecurityFlag = false;
}
var type = field.getGenericType();
// field必须泛型类
AssertionUtils.isTrue(type instanceof ParameterizedType, "[class:{}] type declaration is incorrect, not a generic class[field:{}]", clazz.getCanonicalName(), field.getName());
@@ -520,9 +525,9 @@ public class OrmManager implements IOrmManager {
checkSubEntity(clazz, types[0]);
} else if (Map.class.isAssignableFrom(fieldType)) {
// 必须是Map接口类型
if (!fieldType.equals(Map.class)) {
throw new RunException("[class:{}] type declaration is incorrect, and it must be a Map interface type", clazz.getCanonicalName());
// 是Map接口类型
if (fieldType.equals(Map.class)) {
concurrentSecurityFlag=false;
}
var type = field.getGenericType();
@@ -543,30 +548,34 @@ public class OrmManager implements IOrmManager {
if (!ClassUtils.isBaseType((Class<?>) keyType)) {
throw new RunException("[class:{}] type declaration is incorrect, and the key type of the Map must be the Base type", clazz.getCanonicalName());
}
checkSubEntity(clazz, valueType);
if (concurrentSecurityFlag) {
concurrentSecurityFlag = checkSubEntity(clazz, valueType);
}
} else if (ObjectId.class.isAssignableFrom(fieldType)) {
// do nothing
} else {
checkEntity(fieldType);
}
}
if (!concurrentSecurityFlag) {
logger.warn("class[{}] has collection not declared with specified implementation, deserialization defaults to using the thread unsafe implementation", clazz.getSimpleName());
}
}
private void checkSubEntity(Class<?> currentEntityClass, Type type) {
private boolean checkSubEntity(Class<?> currentEntityClass, Type type) {
if (type instanceof ParameterizedType) {
// 泛型类
Class<?> clazz = (Class<?>) ((ParameterizedType) type).getRawType();
if (Set.class.equals(clazz)) {
if (Set.class.isAssignableFrom(clazz)) {
// Set<Set<String>>
checkSubEntity(currentEntityClass, ((ParameterizedType) type).getActualTypeArguments()[0]);
return;
} else if (List.class.equals(clazz)) {
return clazz.equals(Set.class);
} else if (List.class.isAssignableFrom(clazz)) {
// List<List<String>>
checkSubEntity(currentEntityClass, ((ParameterizedType) type).getActualTypeArguments()[0]);
return;
} else if (Map.class.equals(clazz)) {
return clazz.equals(List.class);
} else if (Map.class.isAssignableFrom(clazz)) {
// Map<List<String>, List<String>>
var types = ((ParameterizedType) type).getActualTypeArguments();
var keyType = types[0];
@@ -575,13 +584,13 @@ public class OrmManager implements IOrmManager {
throw new RunException("The key of the map in the ORM must be of the Base type");
}
checkSubEntity(currentEntityClass, valueType);
return;
return clazz.equals(Map.class);
}
} else if (type instanceof Class) {
Class<?> clazz = ((Class<?>) type);
if (isBaseType(clazz)) {
// do nothing
return;
return true;
} else if (clazz.getComponentType() != null) {
// ORM不支持多维数组或集合嵌套数组类型,仅支持一维数组
throw new RunException("[type:{}] does not support multi-dimensional arrays or nested arrays, and only supports one-dimensional arrays", type);
@@ -590,7 +599,7 @@ public class OrmManager implements IOrmManager {
throw new RunException("ORMs do not support the combination of arrays and collections with the [type:{}] type", type);
} else {
checkEntity(clazz);
return;
return true;
}
}
throw new RunException("[type:{}] is incorrect", type);
@@ -63,6 +63,7 @@ public class EntityDef {
public IEntity<?> newEntity(Object id) {
var entity = ReflectionUtils.newInstance(clazz);
var idFields = ReflectionUtils.getFieldsByAnnoInPOJOClass(clazz, Id.class);
ReflectionUtils.makeAccessible(idFields[0]);
ReflectionUtils.setField(idFields[0], entity, id);
return entity;
}
@@ -27,6 +27,8 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
@Ignore
public class MapTest {
@@ -54,6 +56,22 @@ public class MapTest {
entity.setList(List.of(1, 2, 3));
CopyOnWriteArrayList<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
copyOnWriteArrayList.add(1);
copyOnWriteArrayList.add(2);
entity.setCopyOnWriteArrayList(copyOnWriteArrayList);
ConcurrentHashMap<Long,Integer> concurrentHashMap=new ConcurrentHashMap<>();
concurrentHashMap.put(1L,1);
concurrentHashMap.put(2L,2);
entity.setConcurrentHashMap(concurrentHashMap);
ConcurrentHashMap<Long,ConcurrentHashMap<Integer,Integer>> concurrentHashMapConcurrentHashMap=new ConcurrentHashMap<>();
ConcurrentHashMap<Integer, Integer> conMap = new ConcurrentHashMap<>();
conMap.put(1,1);
concurrentHashMapConcurrentHashMap.putIfAbsent(1L,conMap);
entity.setConcurrentHashMapAndConcurrentHashMap(concurrentHashMapConcurrentHashMap);
var bagMap = new HashMap<String, BagItem>();
entity.setBagMap(bagMap);
@@ -19,6 +19,7 @@ import com.zfoo.orm.anno.Persister;
import com.zfoo.orm.model.IEntity;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
@EntityCache(persister = @Persister("time30s"))
@@ -26,7 +27,13 @@ public class MapEntity implements IEntity<Long> {
@Id
private long id;
private List<Integer> list = new CopyOnWriteArrayList<>();
private List<Integer> list = new ArrayList<>();
private CopyOnWriteArrayList<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
private ConcurrentHashMap<Long, Integer> concurrentHashMap = new ConcurrentHashMap<>();
private ConcurrentHashMap<Long, ConcurrentHashMap<Integer,Integer>> concurrentHashMapAndConcurrentHashMap = new ConcurrentHashMap<>();
private Map<String, BagItem> bagMap = new HashMap<>();
private Map<String, Map<String, String>> baseMap = new HashMap<>();
@@ -168,6 +175,31 @@ public class MapEntity implements IEntity<Long> {
this.doubleBagMap = doubleBagMap;
}
public CopyOnWriteArrayList<Integer> getCopyOnWriteArrayList() {
return copyOnWriteArrayList;
}
public void setCopyOnWriteArrayList(CopyOnWriteArrayList<Integer> copyOnWriteArrayList) {
this.copyOnWriteArrayList = copyOnWriteArrayList;
}
public ConcurrentHashMap<Long, Integer> getConcurrentHashMap() {
return concurrentHashMap;
}
public void setConcurrentHashMap(ConcurrentHashMap<Long, Integer> concurrentHashMap) {
this.concurrentHashMap = concurrentHashMap;
}
public ConcurrentHashMap<Long, ConcurrentHashMap<Integer, Integer>> getConcurrentHashMapAndConcurrentHashMap() {
return concurrentHashMapAndConcurrentHashMap;
}
public void setConcurrentHashMapAndConcurrentHashMap(ConcurrentHashMap<Long, ConcurrentHashMap<Integer, Integer>> concurrentHashMapAndConcurrentHashMap) {
this.concurrentHashMapAndConcurrentHashMap = concurrentHashMapAndConcurrentHashMap;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;