Browse Source

fix typeUtil

Looly 5 years ago
parent
commit
784ad3e8f9

+ 1 - 1
CHANGELOG.md

@@ -15,7 +15,7 @@
 * 【extra 】     SpringUtil增加注册bean(pr#174@Gitee)
 * 【core  】     修改NetUtil.getMacAddress避免空指针(issue#1057@Github)
 * 【core  】     增加EnumItem接口,枚举扩展转换,增加SPI自定义转换(pr#173@Github)
-* 【core  】     TypeUtil增加getActualTypeMap方法
+* 【core  】     TypeUtil增加getActualType,增加ActualTypeMapperPool类(issue#I1TBWH@Gitee)
 
 ### Bug修复
 * 【core  】     重新整理农历节假日,解决一个pr过来的玩笑导致的问题

+ 1 - 21
hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java

@@ -7,10 +7,8 @@ import cn.hutool.core.bean.copier.provider.MapValueProvider;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.convert.Convert;
 import cn.hutool.core.exceptions.UtilException;
-import cn.hutool.core.lang.ParameterizedTypeImpl;
 import cn.hutool.core.lang.copier.Copier;
 import cn.hutool.core.map.MapUtil;
-import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.ModifierUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
@@ -19,9 +17,7 @@ import cn.hutool.core.util.TypeUtil;
 import java.io.Serializable;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
-import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Map;
@@ -246,24 +242,8 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
 
 			// 获取目标字段真实类型
 			Type fieldType = (null == setterMethod) ? TypeUtil.getType(field) : TypeUtil.getFirstParamType(setterMethod);
-			if (fieldType instanceof ParameterizedType) {
-				// 字段类型为泛型参数类型,解析对应泛型类型为真实类型,类似于List<T> a
-				final ParameterizedType fieldParameterizedType = (ParameterizedType) fieldType;
-				Type[] actualTypeArguments = fieldParameterizedType.getActualTypeArguments();
-				if (TypeUtil.hasTypeVeriable(actualTypeArguments)) {
-					// 泛型对象中含有未被转换的泛型变量
-					actualTypeArguments = TypeUtil.getActualTypes(this.destType, field.getDeclaringClass(), fieldParameterizedType.getActualTypeArguments());
-					if (ArrayUtil.isNotEmpty(actualTypeArguments)) {
-						// 替换泛型变量为实际类型
-						fieldType = new ParameterizedTypeImpl(actualTypeArguments, fieldParameterizedType.getOwnerType(), fieldParameterizedType.getRawType());
-					}
-				}
-			} else if (fieldType instanceof TypeVariable) {
-				// 字段类型为泛型,查找其真实类型(适用于泛型方法定义于泛型父类),类似于T a
-				fieldType = TypeUtil.getActualType(this.destType, field.getDeclaringClass(), fieldType);
-			}
+			fieldType = TypeUtil.getActualType(this.destType ,fieldType);
 
-			//
 			value = valueProvider.value(providerKey, fieldType);
 			if (null == value && copyOptions.ignoreNullValue) {
 				continue;// 当允许跳过空时,跳过

+ 1 - 1
hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java

@@ -2023,7 +2023,7 @@ public class CollUtil {
 		if (null == collection || null == value) {
 			return collection;
 		}
-		if (TypeUtil.isUnknow(elementType)) {
+		if (TypeUtil.isUnknown(elementType)) {
 			// 元素类型为空时,使用Object类型来接纳所有类型
 			elementType = Object.class;
 		}

+ 2 - 2
hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java

@@ -226,14 +226,14 @@ public class ConverterRegistry implements Serializable {
 	 */
 	@SuppressWarnings("unchecked")
 	public <T> T convert(Type type, Object value, T defaultValue, boolean isCustomFirst) throws ConvertException {
-		if (TypeUtil.isUnknow(type) && null == defaultValue) {
+		if (TypeUtil.isUnknown(type) && null == defaultValue) {
 			// 对于用户不指定目标类型的情况,返回原值
 			return (T) value;
 		}
 		if (ObjectUtil.isNull(value)) {
 			return defaultValue;
 		}
-		if (TypeUtil.isUnknow(type)) {
+		if (TypeUtil.isUnknown(type)) {
 			type = defaultValue.getClass();
 		}
 

+ 1 - 1
hutool-core/src/main/java/cn/hutool/core/convert/impl/AtomicReferenceConverter.java

@@ -23,7 +23,7 @@ public class AtomicReferenceConverter extends AbstractConverter<AtomicReference>
 		//尝试将值转换为Reference泛型的类型
 		Object targetValue = null;
 		final Type paramType = TypeUtil.getTypeArgument(AtomicReference.class);
-		if(false == TypeUtil.isUnknow(paramType)){
+		if(false == TypeUtil.isUnknown(paramType)){
 			targetValue = ConverterRegistry.getInstance().convert(paramType, value);
 		}
 		if(null == targetValue){

+ 2 - 2
hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java

@@ -86,8 +86,8 @@ public class MapConverter extends AbstractConverter<Map<?, ?>> {
 		Object key;
 		Object value;
 		for (Entry<?, ?> entry : srcMap.entrySet()) {
-			key = TypeUtil.isUnknow(this.keyType) ? entry.getKey() : convert.convert(this.keyType, entry.getKey());
-			value = TypeUtil.isUnknow(this.valueType) ? entry.getValue() : convert.convert(this.valueType, entry.getValue());
+			key = TypeUtil.isUnknown(this.keyType) ? entry.getKey() : convert.convert(this.keyType, entry.getKey());
+			value = TypeUtil.isUnknown(this.valueType) ? entry.getValue() : convert.convert(this.valueType, entry.getValue());
 			targetMap.put(key, value);
 		}
 	}

+ 1 - 1
hutool-core/src/main/java/cn/hutool/core/convert/impl/ReferenceConverter.java

@@ -37,7 +37,7 @@ public class ReferenceConverter extends AbstractConverter<Reference> {
 		//尝试将值转换为Reference泛型的类型
 		Object targetValue = null;
 		final Type paramType = TypeUtil.getTypeArgument(targetType);
-		if(false == TypeUtil.isUnknow(paramType)){
+		if(false == TypeUtil.isUnknown(paramType)){
 			targetValue = ConverterRegistry.getInstance().convert(paramType, value);
 		}
 		if(null == targetValue){

+ 26 - 0
hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java

@@ -366,6 +366,19 @@ public class CalendarUtil {
 	 * @param dateField {@link DateField}
 	 * @return 字段最小值
 	 * @see Calendar#getActualMinimum(int)
+	 * @since 5.4.2
+	 */
+	public static int getBeginValue(Calendar calendar, DateField dateField) {
+		return getBeginValue(calendar, dateField.getValue());
+	}
+
+	/**
+	 * 获取指定日期字段的最小值,例如分钟的最小值是0
+	 *
+	 * @param calendar  {@link Calendar}
+	 * @param dateField {@link DateField}
+	 * @return 字段最小值
+	 * @see Calendar#getActualMinimum(int)
 	 * @since 4.5.7
 	 */
 	public static int getBeginValue(Calendar calendar, int dateField) {
@@ -382,6 +395,19 @@ public class CalendarUtil {
 	 * @param dateField {@link DateField}
 	 * @return 字段最大值
 	 * @see Calendar#getActualMaximum(int)
+	 * @since 5.4.2
+	 */
+	public static int getEndValue(Calendar calendar, DateField dateField) {
+		return getEndValue(calendar, dateField.getValue());
+	}
+
+	/**
+	 * 获取指定日期字段的最大值,例如分钟的最大值是59
+	 *
+	 * @param calendar  {@link Calendar}
+	 * @param dateField {@link DateField}
+	 * @return 字段最大值
+	 * @see Calendar#getActualMaximum(int)
 	 * @since 4.5.7
 	 */
 	public static int getEndValue(Calendar calendar, int dateField) {

+ 12 - 0
hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java

@@ -1916,6 +1916,18 @@ public class DateUtil extends CalendarUtil {
 		return Year.of(year).length();
 	}
 
+	/**
+	 * 获得指定月份的总天数
+	 *
+	 * @param month 年份
+	 * @param isLeapYear 是否闰年
+	 * @return 天
+	 * @since 5.4.2
+	 */
+	public static int lengthOfMonth(int month, boolean isLeapYear) {
+		return java.time.Month.of(month).length(isLeapYear);
+	}
+
 	// ------------------------------------------------------------------------ Private method start
 
 	/**

+ 101 - 0
hutool-core/src/main/java/cn/hutool/core/lang/reflect/ActualTypeMapperPool.java

@@ -0,0 +1,101 @@
+package cn.hutool.core.lang.reflect;
+
+import cn.hutool.core.lang.SimpleCache;
+import cn.hutool.core.util.TypeUtil;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 泛型变量和泛型实际类型映射关系缓存
+ *
+ * @author looly
+ * @since 5.4.2
+ */
+public class ActualTypeMapperPool {
+
+	private static final SimpleCache<Type, Map<Type, Type>> cache = new SimpleCache<>();
+
+	/**
+	 * 获取泛型变量和泛型实际类型的对应关系Map
+	 *
+	 * @param type 被解析的包含泛型参数的类
+	 * @return 泛型对应关系Map
+	 */
+	public static Map<Type, Type> get(Type type) {
+		return cache.get(type, () -> createTypeMap(type));
+	}
+
+	/**
+	 * 获得泛型变量对应的泛型实际类型,如果此变量没有对应的实际类型,返回null
+	 *
+	 * @param type        类
+	 * @param typeVariable 泛型变量,例如T等
+	 * @return 实际类型,可能为Class等
+	 */
+	public static Type getActualType(Type type, TypeVariable<?> typeVariable) {
+		final Map<Type, Type> typeTypeMap = get(type);
+		Type result = typeTypeMap.get(typeVariable);
+		while (result instanceof TypeVariable) {
+			result = typeTypeMap.get(result);
+		}
+		return result;
+	}
+
+	/**
+	 * 获取指定泛型变量对应的真实类型<br>
+	 * 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型<br>
+	 *
+	 * @param type         真实类型所在类,此类中记录了泛型参数对应的实际类型
+	 * @param typeVariables 泛型变量,需要的实际类型对应的泛型参数
+	 * @return 给定泛型参数对应的实际类型,如果无对应类型,对应位置返回null
+	 */
+	public static Type[] getActualTypes(Type type, Type... typeVariables) {
+		// 查找方法定义所在类或接口中此泛型参数的位置
+		final Type[] result = new Type[typeVariables.length];
+		for (int i = 0; i < typeVariables.length; i++) {
+			result[i] = (typeVariables[i] instanceof TypeVariable)
+					? getActualType(type, (TypeVariable<?>) typeVariables[i])
+					: typeVariables[i];
+		}
+		return result;
+	}
+
+	/**
+	 * 创建类中所有的泛型变量和泛型实际类型的对应关系Map
+	 *
+	 * @param type 被解析的包含泛型参数的类
+	 * @return 泛型对应关系Map
+	 */
+	private static Map<Type, Type> createTypeMap(Type type) {
+		final Map<Type, Type> typeMap = new HashMap<>();
+
+		// 按继承层级寻找泛型变量和实际类型的对应关系
+		// 在类中,对应关系分为两类:
+		// 1. 父类定义变量,子类标注实际类型
+		// 2. 父类定义变量,子类继承这个变量,让子类的子类去标注,以此类推
+		// 此方法中我们将每一层级的对应关系全部加入到Map中,查找实际类型的时候,根据传入的泛型变量,
+		// 找到对应关系,如果对应的是继承的泛型变量,则递归继续找,直到找到实际或返回null为止。
+		// 如果传入的非Class,例如TypeReference,获取到泛型参数中实际的泛型对象类,继续按照类处理
+		while (null != type) {
+			final ParameterizedType parameterizedType = TypeUtil.toParameterizedType(type);
+			if(null == parameterizedType){
+				break;
+			}
+			final Type[] typeArguments = parameterizedType.getActualTypeArguments();
+			final Class<?> rawType = (Class<?>) parameterizedType.getRawType();
+			final Type[] typeParameters = rawType.getTypeParameters();
+
+			for (int i = 0; i < typeParameters.length; i++) {
+				typeMap.put(typeParameters[i], typeArguments[i]);
+			}
+
+			type = rawType;
+		}
+
+		return typeMap;
+	}
+}

+ 7 - 0
hutool-core/src/main/java/cn/hutool/core/lang/reflect/package-info.java

@@ -0,0 +1,7 @@
+/**
+ * 提供反射相关功能对象和类
+ *
+ * @author looly
+ * @since 5.4.2
+ */
+package cn.hutool.core.lang.reflect;

+ 80 - 85
hutool-core/src/main/java/cn/hutool/core/util/TypeUtil.java

@@ -1,6 +1,7 @@
 package cn.hutool.core.util;
 
-import cn.hutool.core.map.TableMap;
+import cn.hutool.core.lang.ParameterizedTypeImpl;
+import cn.hutool.core.lang.reflect.ActualTypeMapperPool;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
@@ -8,6 +9,7 @@ import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 import java.lang.reflect.WildcardType;
+import java.util.Map;
 
 /**
  * 针对 {@link Type} 的工具类封装<br>
@@ -282,117 +284,110 @@ public class TypeUtil {
 	}
 
 	/**
-	 * 获取泛型变量和真实类型的对应表,使用{@link TableMap}表示,key不会重复<br>
-	 * 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型<br>
-	 * 使用此方法注意:
-	 *
-	 * <pre>
-	 * 1. typeDefineClass必须是clazz的父类或者clazz实现的接口
-	 * </pre>
+	 * 是否未知类型<br>
+	 * type为null或者{@link TypeVariable} 都视为未知类型
 	 *
-	 * @param actualType      真实类型所在类,此类中记录了泛型参数对应的实际类型
-	 * @param typeDefineClass 泛型变量声明所在类或接口,此类中定义了泛型类型
-	 * @return 给定泛型参数对应的实际类型,如果无对应类型,返回null
-	 * @since 5.4.1
+	 * @param type Type类型
+	 * @return 是否未知类型
+	 * @since 4.5.2
 	 */
-	public static TableMap<String, Type> getActualTypeMap(Type actualType, Class<?> typeDefineClass) {
-		if (false == typeDefineClass.isAssignableFrom(getClass(actualType))) {
-			throw new IllegalArgumentException("Parameter [superClass] must be assignable from [clazz]");
-		}
-
-		// 泛型参数标识符列表
-		final TypeVariable<?>[] typeVars = typeDefineClass.getTypeParameters();
-		if (ArrayUtil.isEmpty(typeVars)) {
-			return new TableMap<>(0);
-		}
-
-		// 实际类型列表
-		final Type[] actualTypeArguments = TypeUtil.getTypeArguments(actualType);
-		if (ArrayUtil.isEmpty(actualTypeArguments)) {
-			return new TableMap<>(0);
-		}
-
-		return new TableMap<>(ArrayUtil.map(typeVars, String.class, TypeVariable::getName), actualTypeArguments);
+	public static boolean isUnknown(Type type) {
+		return null == type || type instanceof TypeVariable;
 	}
 
 	/**
-	 * 获取指定泛型变量对应的真实类型<br>
-	 * 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型<br>
-	 * 使用此方法注意:
-	 *
-	 * <pre>
-	 * 1. superClass必须是clazz的父类或者clazz实现的接口
-	 * 2. typeVariable必须在superClass中声明
-	 * </pre>
+	 * 指定泛型数组中是否含有泛型变量
 	 *
-	 * @param actualType      真实类型所在类,此类中记录了泛型参数对应的实际类型
-	 * @param typeDefineClass 泛型变量声明所在类或接口,此类中定义了泛型类型
-	 * @param typeVariables   泛型变量,需要的实际类型对应的泛型参数
-	 * @return 给定泛型参数对应的实际类型,如果无对应类型,返回null
+	 * @param types 泛型数组
+	 * @return 是否含有泛型变量
 	 * @since 4.5.7
 	 */
-	public static Type[] getActualTypes(Type actualType, Class<?> typeDefineClass, Type... typeVariables) {
-		final TableMap<String, Type> tableMap = getActualTypeMap(actualType, typeDefineClass);
-
-		// 查找方法定义所在类或接口中此泛型参数的位置
-		final Type[] result = new Type[typeVariables.length];
-		for (int i = 0; i < typeVariables.length; i++) {
-			result[i] = (typeVariables[i] instanceof TypeVariable)
-					? tableMap.get(((TypeVariable<?>) typeVariables[i]).getName())
-					: typeVariables[i];
+	public static boolean hasTypeVeriable(Type... types) {
+		for (Type type : types) {
+			if (type instanceof TypeVariable) {
+				return true;
+			}
 		}
-		return result;
+		return false;
 	}
 
 	/**
-	 * 获取指定泛型变量对应的真实类型<br>
-	 * 由于子类中泛型参数实现和父类(接口)中泛型定义位置是一一对应的,因此可以通过对应关系找到泛型实现类型<br>
-	 * 使用此方法注意:
+	 * 获取泛型变量和泛型实际类型的对应关系Map
 	 *
-	 * <pre>
-	 * 1. superClass必须是clazz的父类或者clazz实现的接口
-	 * 2. typeVariable必须在superClass中声明
-	 * </pre>
+	 * @param clazz 被解析的包含泛型参数的类
+	 * @return 泛型对应关系Map
+	 */
+	public static Map<Type, Type> getTypeMap(Class<?> clazz) {
+		return ActualTypeMapperPool.get(clazz);
+	}
+
+	/**
+	 * 获得泛型字段对应的泛型实际类型,如果此变量没有对应的实际类型,返回null
 	 *
-	 * @param actualType      真实类型所在类,此类中记录了泛型参数对应的实际类型
-	 * @param typeDefineClass 泛型变量声明所在类或接口,此类中定义了泛型类型
-	 * @param typeVariable    泛型变量,需要的实际类型对应的泛型参数
-	 * @return 给定泛型参数对应的实际类型
-	 * @since 4.5.2
+	 * @param type 实际类型明确的类
+	 * @param field 字段
+	 * @return 实际类型,可能为Class等
 	 */
-	public static Type getActualType(Type actualType, Class<?> typeDefineClass, Type typeVariable) {
-		final Type[] types = getActualTypes(actualType, typeDefineClass, typeVariable);
-		if (ArrayUtil.isNotEmpty(types)) {
-			return types[0];
+	public static Type getActualType(Type type, Field field) {
+		if(null == field){
+			return null;
 		}
-		return null;
+		return getActualType(ObjectUtil.defaultIfNull(type, field.getDeclaringClass()), field.getGenericType());
 	}
 
 	/**
-	 * 是否未知类型<br>
-	 * type为null或者{@link TypeVariable} 都视为未知类型
+	 * 获得泛型变量对应的泛型实际类型,如果此变量没有对应的实际类型,返回null
+	 * 此方法可以处理
 	 *
-	 * @param type Type类型
-	 * @return 是否未知类型
-	 * @since 4.5.2
+	 * @param type 
+	 * @param typeVariable 泛型变量,例如T等
+	 * @return 实际类型,可能为Class等
 	 */
-	public static boolean isUnknow(Type type) {
-		return null == type || type instanceof TypeVariable;
+	public static Type getActualType(Type type, Type typeVariable) {
+		if (typeVariable instanceof ParameterizedType) {
+			return getActualType(type, (ParameterizedType)typeVariable);
+		}
+
+		if (typeVariable instanceof TypeVariable) {
+			return ActualTypeMapperPool.getActualType(type, (TypeVariable<?>) typeVariable);
+		}
+
+		// 没有需要替换的泛型变量,原样输出
+		return typeVariable;
 	}
 
 	/**
-	 * 指定泛型数组中是否含有泛型变量
+	 * 获得泛型变量对应的泛型实际类型,如果此变量没有对应的实际类型,返回null
+	 * 此方法可以处理
 	 *
-	 * @param types 泛型数组
-	 * @return 是否含有泛型变量
-	 * @since 4.5.7
+	 * @param type
+	 * @param parameterizedType 泛型变量,例如List&lt;T&gt;等
+	 * @return 实际类型,可能为Class等
 	 */
-	public static boolean hasTypeVeriable(Type... types) {
-		for (Type type : types) {
-			if (type instanceof TypeVariable) {
-				return true;
+	public static Type getActualType(Type type, ParameterizedType parameterizedType) {
+		// 字段类型为泛型参数类型,解析对应泛型类型为真实类型,类似于List<T> a
+		Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
+
+		// 泛型对象中含有未被转换的泛型变量
+		if (TypeUtil.hasTypeVeriable(actualTypeArguments)) {
+			actualTypeArguments = getActualTypes(type , parameterizedType.getActualTypeArguments());
+			if (ArrayUtil.isNotEmpty(actualTypeArguments)) {
+				// 替换泛型变量为实际类型,例如List<T>变为List<String>
+				parameterizedType = new ParameterizedTypeImpl(actualTypeArguments, parameterizedType.getOwnerType(), parameterizedType.getRawType());
 			}
 		}
-		return false;
+
+		return parameterizedType;
+	}
+
+	/**
+	 * 获得泛型变量对应的泛型实际类型,如果此变量没有对应的实际类型,返回null
+	 *
+	 * @param type        类
+	 * @param typeVariables 泛型变量数组,例如T等
+	 * @return 实际类型数组,可能为Class等
+	 */
+	public static Type[] getActualTypes(Type type, Type... typeVariables) {
+		return ActualTypeMapperPool.getActualTypes(type, typeVariables);
 	}
 }

+ 24 - 0
hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java

@@ -446,4 +446,28 @@ public class BeanUtilTest {
 		BeanUtil.setProperty(resultMap, "codeList[0].name", "张三");
 		Console.log(resultMap);
 	}
+
+	@Test
+	public void beanCopyTest(){
+		final Station station = new Station();
+		station.setId(123456L);
+
+		final Station station2 = new Station();
+
+		BeanUtil.copyProperties(station, station2);
+		Assert.assertEquals(new Long(123456L), station2.getId());
+	}
+
+	public static class Station extends Tree<Station, Long> {
+
+	}
+
+	public static class Tree<E, T> extends Entity<T> {
+
+	}
+
+	@Data
+	public static class Entity<T>{
+		private T id;
+	}
 }

+ 6 - 7
hutool-core/src/test/java/cn/hutool/core/util/TypeUtilTest.java

@@ -60,24 +60,23 @@ public class TypeUtilTest {
 
 	@Test
 	public void getActualTypesTest(){
-		final Type idType = TypeUtil.getActualType(
-				Station.class,
-				Tree.class,
-				TypeUtil.getFieldType(Station.class, "id"));
+		// 测试多层级泛型参数是否能获取成功
+		Type idType = TypeUtil.getActualType(Level3.class,
+				ReflectUtil.getField(Level3.class, "id"));
 
 		Assert.assertEquals(Long.class, idType);
 	}
 
-	public static class Station extends Tree<Station, Long>{
+	public static class Level3 extends Level2<Level3>{
 
 	}
 
-	public static class Tree<E, T> extends Entity<T>{
+	public static class Level2<E> extends Level1<Long>{
 
 	}
 
 	@Data
-	public static class Entity<T>{
+	public static class Level1<T>{
 		private T id;
 	}