简体   繁体   English

如何确定 Java 中通用字段的类型?

[英]How can I determine the type of a generic field in Java?

I have been trying to determine the type of a field in a class.我一直在尝试确定类中字段的类型。 I've seen all the introspection methods but haven't quite figured out how to do it.我已经看到了所有的内省方法,但还没有完全弄清楚如何去做。 This is going to be used to generate xml/json from a java class.这将用于从 Java 类生成 xml/json。 I've looked at a number of the questions here but haven't found exactly what I need.我在这里查看了许多问题,但还没有找到我需要的确切内容。

Example:例子:

class Person {
    public final String name;
    public final List<Person> children;
}

When I marshall this object, I need to know that the chidren field is a list of objects of type Person , so I can marshall it properly.当我编组这个对象时,我需要知道chidren字段是一个Person类型的对象列表,所以我可以正确地编组它。

I had tried我试过了

for (Field field : Person.class.getDeclaredFields()) {
    System.out.format("Type: %s%n", field.getType());
}

But this will only tell me that it's a List , not a List of Person s但这只会告诉我这是一个List ,而不是List of Person s

Thanks谢谢

Have a look at Obtaining Field Types from the Java Tutorial Trail: The Reflection API .从 Java Tutorial Trail: The Reflection API 中查看获取字段类型

Basically, what you need to do is to get all java.lang.reflect.Field of your class and call Field#getType() on each of them (check edit below).基本上,您需要做的是获取类的所有java.lang.reflect.Field 并在每个 类上 调用 Field#getType() (检查下面的编辑)。 To get all object fields including public, protected, package and private access fields, simply use Class.getDeclaredFields() .要获取所有对象字段,包括公共、受保护、包和私有访问字段,只需使用Class.getDeclaredFields() Something like this:像这样的东西:

for (Field field : Person.class.getDeclaredFields()) {
    System.out.format("Type: %s%n", field.getType());
    System.out.format("GenericType: %s%n", field.getGenericType());
}

EDIT: As pointed out by wowest in a comment, you actually need to call Field#getGenericType() , check if the returned Type is a ParameterizedType and then grab the parameters accordingly.编辑:正如wowest在评论中指出的那样,您实际上需要调用Field#getGenericType() ,检查返回的Type是否为ParameterizedType ,然后相应地获取参数。 Use ParameterizedType#getRawType() and ParameterizedType#getActualTypeArgument() to get the raw type and an array of the types argument of a ParameterizedType respectively.使用ParameterizedType#getRawType()ParameterizedType#getActualTypeArgument()得到的原始类型和的类型自变量的数组ParameterizedType分别。 The following code demonstrates this:以下代码演示了这一点:

for (Field field : Person.class.getDeclaredFields()) {
    System.out.print("Field: " + field.getName() + " - ");
    Type type = field.getGenericType();
    if (type instanceof ParameterizedType) {
        ParameterizedType pType = (ParameterizedType)type;
        System.out.print("Raw type: " + pType.getRawType() + " - ");
        System.out.println("Type args: " + pType.getActualTypeArguments()[0]);
    } else {
        System.out.println("Type: " + field.getType());
    }
}

And would output:并且会输出:

Field: name - Type: class java.lang.String
Field: children - Raw type: interface java.util.List - Type args: class foo.Person

Here's an example that answers my question这是一个回答我的问题的例子

class Person {
  public final String name;
  public final List<Person> children;  
}

//in main
Field[] fields = Person.class.getDeclaredFields();
for (Field field : fields) {
  Type type = field.getGenericType();
  System.out.println("field name: " + field.getName());
  if (type instanceof ParameterizedType) {
    ParameterizedType ptype = (ParameterizedType) type;
    ptype.getRawType();
    System.out.println("-raw type:" + ptype.getRawType());
    System.out.println("-type arg: " + ptype.getActualTypeArguments()[0]);
  } else {
    System.out.println("-field type: " + field.getType());
  }
}

This outputs这输出

field name: name
-field type: class java.lang.String
field name: children
-raw type:interface java.util.List
-type arg: class com.blah.Person

I haven't found any framework who determines a generic field type through the inheritance layers so i've written some method:我还没有找到任何通过继承层确定泛型字段类型的框架,所以我写了一些方法:

This logic determines the type through the field information and the current object class.该逻辑通过字段信息和当前对象类来确定类型。

Listing 1 - logic:清单 1 - 逻辑:

public static Class<?> determineType(Field field, Object object) {
    Class<?> type = object.getClass();
    return (Class<?>) getType(type, field).type;
}

protected static class TypeInfo {
    Type type;
    Type name;

    public TypeInfo(Type type, Type name) {
        this.type = type;
        this.name = name;
    }

}

private static TypeInfo getType(Class<?> clazz, Field field) {
    TypeInfo type = new TypeInfo(null, null);
    if (field.getGenericType() instanceof TypeVariable<?>) {
        TypeVariable<?> genericTyp = (TypeVariable<?>) field.getGenericType();
        Class<?> superClazz = clazz.getSuperclass();

        if (clazz.getGenericSuperclass() instanceof ParameterizedType) {
            ParameterizedType paramType = (ParameterizedType) clazz.getGenericSuperclass();
            TypeVariable<?>[] superTypeParameters = superClazz.getTypeParameters();
            if (!Object.class.equals(paramType)) {
                if (field.getDeclaringClass().equals(superClazz)) {
                    // this is the root class an starting point for this search
                    type.name = genericTyp;
                    type.type = null;
                } else {
                    type = getType(superClazz, field);
                }
            }
            if (type.type == null || type.type instanceof TypeVariable<?>) {
                // lookup if type is not found or type needs a lookup in current concrete class
                for (int j = 0; j < superClazz.getTypeParameters().length; ++j) {
                    TypeVariable<?> superTypeParam = superTypeParameters[j];
                    if (type.name.equals(superTypeParam)) {
                        type.type = paramType.getActualTypeArguments()[j];
                        Type[] typeParameters = clazz.getTypeParameters();
                        if (typeParameters.length > 0) {
                            for (Type typeParam : typeParameters) {
                                TypeVariable<?> objectOfComparison = superTypeParam;
                                if(type.type instanceof TypeVariable<?>) {
                                    objectOfComparison = (TypeVariable<?>)type.type;
                                }
                                if (objectOfComparison.getName().equals(((TypeVariable<?>) typeParam).getName())) {
                                    type.name = typeParam;
                                    break;
                                }
                            }
                        }
                        break;
                    }
                }
            }
        }
    } else {
        type.type = field.getGenericType();
    }

    return type;
}

Listing 2 - Samples / Tests:清单 2 - 样本/测试:

class GenericSuperClass<E, T, A> {
    T t;
    E e;
    A a;
    BigDecimal b;
}

class GenericDefinition extends GenericSuperClass<Integer, Integer, Integer> {

}

@Test
public void testSimpleInheritanceTypeDetermination() {
    GenericDefinition gd = new GenericDefinition();
    Field field = ReflectionUtils.getField(gd, "t");
    Class<?> clazz = ReflectionUtils.determineType(field, gd);
    Assert.assertEquals(clazz, Integer.class);
    field = ReflectionUtils.getField(gd, "b");
    clazz = ReflectionUtils.determineType(field, gd);
    Assert.assertEquals(clazz, BigDecimal.class);
}

class MiddleClass<A, E> extends GenericSuperClass<E, Integer, A> { }

// T = Integer, E = String, A = Double
class SimpleTopClass extends MiddleClass<Double, String> { }

@Test
public void testSimple2StageInheritanceTypeDetermination() {
    SimpleTopClass stc = new SimpleTopClass();
    Field field = ReflectionUtils.getField(stc, "t");
    Class<?> clazz = ReflectionUtils.determineType(field, stc);
    Assert.assertEquals(clazz, Integer.class);
    field = ReflectionUtils.getField(stc, "e");
    clazz = ReflectionUtils.determineType(field, stc);
    Assert.assertEquals(clazz, String.class);
    field = ReflectionUtils.getField(stc, "a");
    clazz = ReflectionUtils.determineType(field, stc);
    Assert.assertEquals(clazz, Double.class);
}

class TopMiddleClass<A> extends MiddleClass<A, Double> { }

// T = Integer, E = Double, A = Float
class ComplexTopClass extends TopMiddleClass<Float> {}

@Test void testComplexInheritanceTypDetermination() {
    ComplexTopClass ctc = new ComplexTopClass();
    Field field = ReflectionUtils.getField(ctc, "t");
    Class<?> clazz = ReflectionUtils.determineType(field, ctc);
    Assert.assertEquals(clazz, Integer.class);
    field = ReflectionUtils.getField(ctc, "e");
    clazz = ReflectionUtils.determineType(field, ctc);
    Assert.assertEquals(clazz, Double.class);
    field = ReflectionUtils.getField(ctc, "a");
    clazz = ReflectionUtils.determineType(field, ctc);
    Assert.assertEquals(clazz, Float.class);
}

class ConfusingClass<A, E> extends MiddleClass<E, A> {}
// T = Integer, E = Double, A = Float ; this class should map between a and e
class TopConfusingClass extends ConfusingClass<Double, Float> {}

@Test
public void testConfusingNamingConvetionWithInheritance() {
    TopConfusingClass tcc = new TopConfusingClass();
    Field field = ReflectionUtils.getField(tcc, "t");
    Class<?> clazz = ReflectionUtils.determineType(field, tcc);
    Assert.assertEquals(clazz, Integer.class);
    field = ReflectionUtils.getField(tcc, "e");
    clazz = ReflectionUtils.determineType(field, tcc);
    Assert.assertEquals(clazz, Double.class);
    field = ReflectionUtils.getField(tcc, "a");
    clazz = ReflectionUtils.determineType(field, tcc);
    Assert.assertEquals(clazz, Float.class);
    field = ReflectionUtils.getField(tcc, "b");
    clazz = ReflectionUtils.determineType(field, tcc);
    Assert.assertEquals(clazz, BigDecimal.class);
}

class Pojo {
    Byte z;
}

@Test
public void testPojoDetermineType() {
    Pojo pojo = new Pojo();
    Field field = ReflectionUtils.getField(pojo, "z");
    Class<?> clazz = ReflectionUtils.determineType(field, pojo);
    Assert.assertEquals(clazz, Byte.class);
}

I'm looking forward to hear your feedback!我期待听到您的反馈!

take this snippet:拿这个片段:

 for (Field field : Person.class.getFields()) {
        System.out.println(field.getType());
 }

the key class is Field关键类是Field

Here's my take.这是我的看法。 It cannot handle every possible case (and surely has some bugs), but it does handle every case that occurs in my code so far.它无法处理所有可能的情况(并且肯定有一些错误),但它确实处理了到目前为止我的代码中出现的所有情况。 That includes these declarations, which should be a good start for many use cases:这包括这些声明,这对于许多用例来说应该是一个好的开始:

  private int                                                primitiveField1;

  private Object                                             field1;
  private List<Integer>                                      field2;
  private Map<Integer, String>                               field3;
  private Map<? extends String, List<Map<Class<?>, Object>>> field4;

  private char[]                                             array1;
  private Character[]                                        array2;
  private Class<? extends Integer>[]                         array3;
  private List<Integer>[]                                    array4;

  private InnerClass<String>                                 innerClass;

Implementation:执行:

  public static String getDeclaration(Field field) {
    return getDeclaration(field.getGenericType());
  }

  private static String getDeclaration(Type genericType) {
    if(genericType instanceof ParameterizedType) {
      // types with parameters
      ParameterizedType parameterizedType = (ParameterizedType) genericType;
      String declaration = parameterizedType.getRawType().getTypeName();
      declaration += "<";

      Type[] typeArgs = parameterizedType.getActualTypeArguments();

      for(int i = 0; i < typeArgs.length; i++) {
        Type typeArg = typeArgs[i];

        if(i > 0) {
          declaration += ", ";
        }

        // note: recursive call
        declaration += getDeclaration(typeArg);
      }

      declaration += ">";
      declaration = declaration.replace('$', '.');
      return declaration;
    }
    else if(genericType instanceof Class<?>) {
      Class<?> clazz = (Class<?>) genericType;

      if(clazz.isArray()) {
        // arrays
        return clazz.getComponentType().getCanonicalName() + "[]";
      }
      else {
        // primitive and types without parameters (normal/standard types)
        return clazz.getCanonicalName();
      }
    }
    else {
      // e.g. WildcardTypeImpl (Class<? extends Integer>)
      return genericType.getTypeName();
    }
  }

As dfa points out, you can get the erased type with java.lang.reflect.Field.getType .正如 dfa 指出的那样,您可以使用java.lang.reflect.Field.getType获得擦除的类型。 You can get the generic type with Field.getGenericType (which may have wildcards and bound generic parameters and all sorts of craziness).您可以使用Field.getGenericType获取泛型类型(它可能有通配符和绑定的泛型参数以及各种疯狂的东西)。 You can get the fields through Class.getDeclaredFields ( Class.getFields will give you public fields (including those of the supertpye) - pointless).您可以通过Class.getDeclaredFields获取字段( Class.getFields将为您提供公共字段(包括 supertpye 的字段) - 毫无意义)。 To get the base type fields, go through Class.getSuperclass .要获取基本类型字段,请通过Class.getSuperclass Note to check modifiers from Field.getModifiers - static fields probably will not be interesting to you.注意检查Field.getModifiers修饰符 - 您可能不会对静态字段感兴趣。

The method field.getGenericType() returns a reference to the Type interface.方法field.getGenericType()返回对Type接口的引用。 The real type could be an instance of TypeVariable or GenericArrayType or ParameterizedType or Class or something else I don't know about at this moment.真正的类型可能是TypeVariableGenericArrayTypeParameterizedTypeClass的实例,或者我目前不知道的其他东西。

Different approaches are needed to retrieve the actual type of field.需要不同的方法来检索字段的实际类型。

Here is my solution for getting information about public fields in the form of a tree of TypeFieldTreeNode objects.这是我以 TypeFieldTreeNode 对象树的形式获取有关公共字段的信息的解决方案。

public class TypeFieldTreeNode {
    public String fieldName;
    public String typeSimpleName;
    public String typeCanonicalName;
    public String typeGenericName;
    public List<TypeFieldTreeNode> children;

    public TypeFieldTreeNode(String fieldName, String typeSimpleName, String typeCanonicalName, String genericTypeName) {
        this.fieldName = fieldName;
        this.typeSimpleName = typeSimpleName;
        this.typeCanonicalName = typeCanonicalName;
        this.typeGenericName = genericTypeName;
        this.children = new ArrayList<>();
    }
}

Main method:主要方法:

private List<TypeFieldTreeNode> getTypeFields(Class<?> clazz, Type genericType,
                                              Map<TypeVariable<?>, Type> actualClassArguments) throws Exception {
    if(clazz == null) { 
        return Collections.emptyList();
    }

    List<Field> fields = Arrays.stream(clazz.getDeclaredFields())
            .filter(f -> Modifier.isPublic(f.getModifiers()) && !Modifier.isFinal(f.getModifiers()))
            .collect(Collectors.toList());

    List<TypeFieldTreeNode> result = new ArrayList<>();
    Map<TypeVariable<?>, Type> classArgumentsMap = mapTypeActualClassArguments(
            clazz, genericType, actualClassArguments);

    for(Field field : fields) {
        result.add(getClassFieldData(field, classArgumentsMap));
    }

    if(clazz.getSuperclass() != null) {
        List<TypeFieldTreeNode> superClassFields =
                getTypeFields(clazz.getSuperclass(), clazz.getGenericSuperclass(), classArgumentsMap);
        result.addAll(superClassFields);
    }
    return result;
}

Next is listing of a core method that binds metadata of type TypeVariable of generic parameters with actual types of generic parameters.接下来是一个核心方法的清单,该方法将泛型参数的 TypeVariable 类型的元数据与泛型参数的实际类型绑定。 Method uses the mapping obtained earlier to restore the actual type of the generic parameter when that type is an instance of TypeVariable:当泛型参数是 TypeVariable 的实例时,方法使用之前获得的映射来恢复泛型参数的实际类型:

private Map<TypeVariable<?>, Type> mapTypeActualClassArguments(Class<?> clazz, Type genericType,
                                                                   Map<TypeVariable<?>, Type> actualClassArguments) throws Exception {
        if(!(genericType instanceof ParameterizedType)) {
            return Collections.emptyMap();
        }

        Map<TypeVariable<?>, Type> result = new HashMap<>();
        Type[] actualTypeParametersTypes = ((ParameterizedType) genericType).getActualTypeArguments();
        TypeVariable<?>[] classTypeParameters = clazz.getTypeParameters();

        for (int i = 0; i < classTypeParameters.length; i++) {
            if(actualTypeParametersTypes[i] instanceof TypeVariable<?>) {
                TypeVariable<?> fieldTypeVariable = (TypeVariable<?>) actualTypeParametersTypes[i];

                if(actualClassArguments.containsKey(fieldTypeVariable))
                    actualTypeParametersTypes[i] = actualClassArguments.get(fieldTypeVariable);
                else
                    throw new Exception(String.format("For generic parameter %s of type %s, the corresponding actual type of generic parameter was not found",
                            classTypeParameters[i].getName(), genericType.getTypeName()));
            }
            result.put(classTypeParameters[i], actualTypeParametersTypes[i]);
        }

        return result;
    }

Get data about a field and all available fields of the class that is the type of this field:获取有关字段和属于该字段类型的类的所有可用字段的数据:

private TypeFieldTreeNode getClassFieldData(Field field, 
                                            Map<TypeVariable<?>, Type> actualClassArguments) throws Exception {
    Class<?> fieldClass = field.getType();
    Type fieldGenericType = field.getGenericType();
    TypeFieldTreeNode result = null;

    // if type of the field is a generic parameter of the class containing the field
    if(fieldGenericType instanceof TypeVariable<?>) {
        Type actualFieldType = null;
        Class<?> actualFieldClass = null;
        Map<TypeVariable<?>, Type> fieldTypeActualClassArguments = new HashMap<>();
        TypeVariable<?> fieldTypeVariable = (TypeVariable<?>) fieldGenericType;

        if(actualClassArguments.containsKey(fieldTypeVariable))
            actualFieldType = actualClassArguments.get(fieldTypeVariable);
        else
            throw new Exception(String.format("For a field %s of type %s from class %s, the corresponding actual type of generic parameter was not found",
                    field.getName(), fieldGenericType.getTypeName(), field.getDeclaringClass().getCanonicalName()));

        // for example, field "myField2" of class MyClass2<MyClass<Integer>> where:
        // public class MyClass2<T> { public T myField2; }
        // public class MyClass<T> { public T myField; }
        if(actualFieldType instanceof ParameterizedType) {
            actualFieldClass = (Class<?>)((ParameterizedType) actualFieldType).getRawType();
            result = new TypeFieldTreeNode(field.getName(), actualFieldClass.getSimpleName(),
                    actualFieldClass.getCanonicalName(), actualFieldType.getTypeName());

            fieldTypeActualClassArguments = mapTypeActualClassArguments(actualFieldClass, actualFieldType, actualClassArguments);
        }
        // for example, field "myField" of class MyClass<Integer> where:
        // public class MyClass<T> { public T myField; }
        else {
            actualFieldClass = (Class<?>) actualFieldType;
            result = new TypeFieldTreeNode(field.getName(), actualFieldClass.getSimpleName(),
                    actualFieldClass.getCanonicalName(), "");
        }

        List<Field> childFields = Arrays.stream(actualFieldClass.getFields())
                .filter(f -> !Modifier.isFinal(f.getModifiers()))
                .collect(Collectors.toList());
        for (Field childField : childFields) {
            result.children.add(getClassFieldData(childField, fieldTypeActualClassArguments));
        }
    }
    // if the field is an array and the type of the elements of the array is a generic parameter of the class containing the field
    // for example, field "myField" of class MyClass<Integer> where:
    // public class MyClass<T> { public T[] myField; }
    else if(fieldGenericType instanceof GenericArrayType) {
        Type genericComponentType = ((GenericArrayType) fieldGenericType).getGenericComponentType();
        if(genericComponentType instanceof TypeVariable<?>) {
            if(actualClassArguments.containsKey(genericComponentType)) {
                Type actualArrayComponentType = actualClassArguments.get(genericComponentType);
                assert !(actualArrayComponentType instanceof ParameterizedType);
                Class<?> actualArrayClass = (Class<?>) actualArrayComponentType;
                result = new TypeFieldTreeNode(field.getName(), actualArrayClass.getSimpleName() + "[]",
                        actualArrayClass.getCanonicalName() + "[]", "");
            }
            else
                throw new Exception(String.format("For a field %s of type %s from class %s, the corresponding actual type of generic parameter was not found",
                        field.getName(), fieldGenericType.getTypeName(), field.getDeclaringClass().getCanonicalName()));
        }
        else
            throw new Exception(String.format("Unknown array genericComponentType: %s", genericComponentType.getClass().getCanonicalName()));
    }
    else {
        result = new TypeFieldTreeNode(field.getName(), fieldClass.getSimpleName(), fieldClass.getCanonicalName(), "");
        Map<TypeVariable<?>, Type> fieldTypeActualClassArguments = new HashMap<>();

        // for example, field "myField2" of class MyClass2<Integer> where:
        // public class MyClass2<T> { public MyClass<T> myField2; }
        // public class MyClass<T> { public T myField; }
        if(fieldGenericType instanceof ParameterizedType) {

            // custom generic type name creator for situations when actual type arguments can be of type TypeVariable
            result.typeGenericName = getGenericTypeName((ParameterizedType)fieldGenericType, actualClassArguments);
            fieldTypeActualClassArguments = mapTypeActualClassArguments(fieldClass, fieldGenericType, actualClassArguments);
        }

        List<Field> childFields = Arrays.stream(fieldClass.getFields()).filter(f -> !Modifier.isFinal(f.getModifiers()))
                .collect(Collectors.toList());
        for (Field childField : childFields) {
            result.children.add(getClassFieldData(childField, fieldTypeActualClassArguments));
        }
    }

    return result;
}

private String getGenericTypeName(ParameterizedType parameterizedType, 
                                  Map<TypeVariable<?>, Type> actualClassArguments) throws Exception  {
    List<String> genericParamJavaTypes = new ArrayList<>();
    for(Type typeArgument : parameterizedType.getActualTypeArguments()) {
        if (typeArgument instanceof TypeVariable<?>) {
            TypeVariable<?> typeVariable = (TypeVariable<?>) typeArgument;
            if(actualClassArguments.containsKey(typeVariable)) {
                typeArgument = actualClassArguments.get(typeVariable);
            } else
                throw new Exception(String.format("For generic parameter %s of type %s, the corresponding actual type of generic parameter was not found",
                        typeArgument.getTypeName(), parameterizedType.getTypeName()));
        }

        if(typeArgument instanceof ParameterizedType) {
            ParameterizedType parameterizedTypeArgument = (ParameterizedType) typeArgument;
            Map<TypeVariable<?>, Type> typeActualClassArguments = mapTypeActualClassArguments(
                    (Class<?>)parameterizedTypeArgument.getRawType(),
                    typeArgument, actualClassArguments);
            genericParamJavaTypes.add(getGenericTypeName((ParameterizedType) typeArgument, typeActualClassArguments));
        }
        else if (typeArgument instanceof Class<?>)
            genericParamJavaTypes.add(((Class<?>) typeArgument).getCanonicalName());
        else
            throw new Exception(String.format("For generic parameter %s of type %s, the corresponding actual type of generic parameter was not found", typeArgument.getTypeName()));
    }

    Class<?> rawType = (Class<?>) parameterizedType.getRawType();
    return rawType.getCanonicalName() + "<" + String.join(", ", genericParamJavaTypes) + ">";
}

Usage:用法:

public List<TypeFieldTreeNode> getReturnTypeFields(Method method) throws Exception {
    return getTypeFields(method.getReturnType(),
            method.getGenericReturnType(), Collections.emptyMap());
}

The solution works as expected for the following test types:该解决方案适用于以下测试类型:

  • MyClass2<MyClass<Integer>, MyClass<Boolean>, Double>
  • MyClass3<MyClass<Integer>, MyClass<Double>>

Where:在哪里:

public class MyClass<T> {
    public T value;
    public List<String> list;
}

public class MyClass2<T, V, E> {
    public T value;
    public List<String> strList;
    public List<V> genericList;
    public int[] intArray;
    public E[] genericArray;
    public MyClass<E> genericClass;
}

public class MyClass3<T, V> extends MyClass2<T, V, Boolean> {
    public T value3;
    public List<V> genericList3;
}
public static Type[] getGenericTypes(Field field) {
    ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
    return actualTypeArguments;
}

class User{ 
    ...
    private Set<Authority> authorities = new HashSet<>();
    ...
}

/// usage
Class c = User.class;
Field field = c.getDeclaredField("authorities");
Type[] types = getGenericTypes(field);
log.info("Types: {}", types); 
/// result
Types: class com.fajar.medicalinventory.entity.Authority

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM