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

我一直在试图确定一个字段的一个类的类型。 我见过所有的内省方法,但还没有完全想通了如何做到这一点。 这将被用于生成从一个Java类的xml / JSON。 我已经看了一些这里的问题,但还没有发现正是我需要的。

例:

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

当我马歇尔这个目标,我需要知道chidren字段类型的对象名单Person ,所以我可以编组得当。

谢谢

--------------解决方案-------------

看一看从Java教程径获取字段类型:反射API。

基本上,你需要做的是让所有java.lang.reflect.Field类和呼叫Field#getType()对他们每个人(查询编辑下文)。 为了让所有的对象领域,包括公共,保护,包装和私营接入领域,简单地使用Class.getDeclaredFields() 事情是这样的:

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

编辑:正如评论指出wowest,你实际上需要调用Field#getGenericType()检查返回TypeParameterizedType然后相应地抓住参数。 使用ParameterizedType#getRawType()ParameterizedType#getActualTypeArgument()来获取原始类型和类型参数的数组ParameterizedType分别。 下面的代码演示了这一点:

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());
}
}

并会输出:

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

借此片段:

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

关键类是场

我还没有发现任何框架谁通过继承层,所以我已经写了一些方法来确定一个通用的字段类型:

这个逻辑确定通过现场信息和当前的对象类的类型。

清单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;
}

清单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);
}

我期待着听到您的意见!

由于DFA所指出的,就可以得到消除类型与java.lang.reflect.Field.getType 你可以得到泛型类型Field.getGenericType可能有通配符和约束泛型参数和各种疯狂)。 你可以通过域Class.getDeclaredFields会给你的公共领域(包括那些supertpye的) -毫无意义)。 Class.getFields 为了得到基本类型的字段,通过Class.getSuperclass 注意检查从修饰符Field.getModifiers -静态字段可能不会吸引您。

下面是回答我的问题的一个例子

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());
}
}

该输出

字段名称:名称
-field类型:类java.lang.String
字段名称:儿童
-raw类型:接口java.util.List中
型精氨酸:类com.blah.Person

下面是Java反射和泛型其中也涵盖了泛型方法和字段类型的稍微长一些的解释:

http://tutorials.jenkov.com/java-reflection/generics.html

如果要比较的字段类型,你应该试试这个

if( field.getType().isAssignableFrom(String.class)){}

要么

if( field.getType().isAssignableFrom(YOURCLASS.class)){}

分类:java的 时间:2012-12-08 人气:0
分享到:

相关文章

Copyright (C) 55228885.com, All Rights Reserved.

55228885 版权所有 京ICP备15002868号

processed in 2.624 (s). 10 q(s)