如果我们提供足够的泛型信息,像Jackson这样的库可以从JSON创建对象。
在杰克逊,我们可以
Class<?>[] parameterTypes;
JavaType type = objectMapper.getTypeFactory().constructParametricType(ObjectClass, parameterTypes);
objectMapper.readValue(json, type);
public class MultiLevelGenericTestData<T, V> {
private GenericTestData<T> tGenericTestData;
private GenericTestData<V> vGenericTestData;
}
public class MultiGenericTestData<K, V> {
private K key;
private V value;
}
public class MultiGenericTestDataSameType<T> {
private GenericTestData<T> genericTestData;
private MultiGenericTestData<T, T> multiGenericTestData;
}
// This method should find all type's class names in the list
// that can be used to construct the object without any issue.
void genericFieldClassNames(List<String> types, List<String> classes, Object payload)
throws IllegalAccessException {
for (Field field : payload.getClass().getDeclaredFields()) {
// ignorefield without annotation
if (!field.isAnnotationPresent(GenericField.class)) {
continue;
}
Type genericType = field.getGenericType();
// not a generic field
if (genericType.equals(field.getType())) {
continue;
}
// null value nothing can be done
Object fieldVal = FieldUtils.readField(field, payload, true);
if (fieldVal == null) {
continue;
}
String genericFieldType = genericType.getTypeName();
Class<?> fieldClass = fieldVal.getClass();
// problematic cases when we start traversing up
if (genericFieldType.endsWith(">")) {
genericFieldClassNames(types, classes, fieldVal);
} else {
// here a check can be added to avoid duplicate type name but as soon as
// we add type genericFieldType check it will fail when we have used similar
// types in construction like MultiGenericTestData<String, String>
types.add(genericFieldType);
classes.add(fieldClass.getName());
}
}
}
MultiLevelGenericTestData<String, String> data;
MultiLevelGenericTestData<String, Integer> data;
在这种情况下,我们应该得到[String,Integer]
MultiGenericTestData<String, String> data;
在这种情况下,我们应该得到[String,String]
MultiGenericTestDataSameType<String> data;
在这种情况下,我们应该得到[String]
MultiGenericTestDataSameType< MultiGenericTestData< String, Integer> > data;
为了进一步澄清,我希望在不创建任何其他类的情况下获取类型信息,并且这些信息应该传递给序列化程序,即我不希望更改类似于[]字节序列化(对象有效负载)
的序列化程序方法签名。我们可以创建任意多的helper类,也可以强制从某个超类扩展有效负载类(超类可以有逻辑来提取通用信息)。
这是一个相当长的答案,但应该让你进入一个很好的起点去做你想做的事情。
在运行时获取泛型类型的“技巧”相当古老,使用的最著名的(我猜)现代库是GSON
和Guava
。我想Jackson
使用了同样的技巧,因为没有其他方法可以做到这一点。
简单地说,您需要这样一个类:
static abstract class MappingRegistrar<IN> {
private final Type type;
protected MappingRegistrar() {
// more will be here shortly
}
// ... more will come here shortly
}
MappingRegistrar<String> one = new MappingRegistrar<>() {};
static abstract class MappingRegistrar<IN> {
private final Type type;
protected MappingRegistrar() {
Class<?> cls = getClass();
Type[] type = ((ParameterizedType) cls.getGenericSuperclass()).getActualTypeArguments();
this.type = type[0];
}
}
static abstract class MappingRegistrar<IN> {
private final Type type;
protected MappingRegistrar() {
Class<?> cls = getClass();
Type[] type = ((ParameterizedType) cls.getGenericSuperclass()).getActualTypeArguments();
this.type = type[0];
}
public void seeIt() {
innerSeeIt(type);
}
private void innerSeeIt(Type type) {
if (type instanceof Class) {
Class<?> cls = (Class<?>) type;
boolean isArray = cls.isArray();
if (isArray) {
System.out.print(cls.getComponentType().getSimpleName() + "[]");
return;
}
System.out.print(cls.getSimpleName());
}
if (type instanceof TypeVariable) {
Type[] bounds = ((TypeVariable<?>) type).getBounds();
String s = Arrays.stream(bounds).map(Type::getTypeName).collect(Collectors.joining(", ", "[", "]"));
System.out.print(s);
}
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
String rawType = parameterizedType.getRawType().getTypeName();
System.out.print(rawType + "<");
Type[] arguments = parameterizedType.getActualTypeArguments();
for (int i = 0; i < arguments.length; ++i) {
innerSeeIt(arguments[i]);
if (i != arguments.length - 1) {
System.out.print(", ");
}
}
System.out.print(">");
//System.out.println(Arrays.toString(arguments));
}
if (type instanceof GenericArrayType) {
// you need to handle this one too
}
if (type instanceof WildcardType) {
// you need to handle this one too, but it isn't trivial
}
}
}
public class Playground2<R extends Number & Serializable> {
public static void main(String[] args) {
new Playground2<Integer>().samples();
}
public void samples() {
MappingRegistrar<String> one = new MappingRegistrar<>() {};
one.seeIt();
System.out.println("\n-------------");
MappingRegistrar<String[]> two = new MappingRegistrar<>() {};
two.seeIt();
System.out.println("\n-------------");
MappingRegistrar<R> three = new MappingRegistrar<>() {};
three.seeIt();
System.out.println("\n-------------");
MappingRegistrar<MultiLevelGenericTestData<String, String>> four = new MappingRegistrar<>() {};
four.seeIt();
System.out.println("\n-------------");
MappingRegistrar<MultiGenericTestDataSameType<MultiGenericTestData<String, Integer>>> five = new MappingRegistrar<>() {};
five.seeIt();
System.out.println("\n-------------");
}
}
结果是:
String
-------------
String[]
-------------
[java.lang.Number, java.io.Serializable]
-------------
Playground2$MultiLevelGenericTestData<String, String>
-------------
Playground2$MultiGenericTestDataSameType<Playground2$MultiGenericTestData<String, Integer>>
-------------
问题内容: 我有一个方法以a 作为参数。 在中,我如何知道a 是还是a 是? 问题答案: 根据用户omain的回答“如果使用<?>,则意味着您将不会在任何地方使用参数化类型。要么转到特定类型(在您的情况下,似乎是),要么转到非常通用的“ 另外,我相信如果您使用问号,编译器将在运行时(类型;有效Java的第119页)消除类型不匹配的情况,绕过擦除,并有效地消除了使用泛型类型所带来的好处? 要回答发问
System.Linq.Enumerable.Cast<T> 强制序列的每个对象转化为目标类型 T 。这是框架的一部分,所以 LINQ 查询中的 IEnumerable (而不是 IEnumerable<T> )才能使用。 Cast<T> 是一个没有约束的泛型方法。这就是限制类型转换使用它。如果你理解 Cast<T> 的这个限制,你会发现你自己想的却不能工作。现实中,它就是该本来那样工作,而不是你
我在我的一个实用程序类中有一个方法,它接受一个集合和一个类对象,并返回一个Iterable实例,该实例可以遍历作为指定类实例的集合的所有成员。其签名为: 这对于大多数用例都非常有效,但现在我需要将其与泛型类
我想使用泛型类作为另一个泛型类的类型参数。 起初,我对类的定义是这样的: 然后我的需求发生了变化,我不得不为我的R类型使用包装器/持有者类 到目前为止,我的尝试:(给出编译时错误:
问题内容: 我刚刚了解了这种美观的语法 用可能是类型的元素来清空。Java的源代码如下所示: 现在,如果我以这种方式编写了一个泛型类型不出现在参数列表中的方法,那么有什么方法可以访问成为的实际类呢? 我的意思是,到目前为止,我编码同一件事的方法是 如果删除了-parameter,我将无法执行。显然我可以 但这给了我通常的警告。好的,在这里有帮助,但是实际上我想对方法的预期返回类型做些事情。如果我添
我试图创建一个Java方法,它接受一个对象类型和它应该转换成的数据类型。 例如,如果我应该能够返回一个值1作为Int或双根据需要。我使用类传递数据类型作为参数。 问题:如何使方法泛型以接受基于输入参数的返回类型? 下面的代码只是一个示例,它可能在语法上不正确,用于解释我的问题。