java - java允许我将此对象分配给此通用字段吗?
问题描述
在我的 POJO 编辑器中,我需要检查用户提供的类名是否可以实例化并分配给通用属性。Guava 反射几乎提供了我需要的一切:我解析类型然后调用proptype.isSupertypeOf(implClazz)
,但这并没有按预期工作。
例如,我有类型标记:java.util.Collection<java.sql.Timestamp>
并且我希望我的检查接受ArrayList
并且扩展 rawArrayList
或ArrayList<Timestamp>
本身的类被参数化,但不接受扩展的类ArrayList<Integer>
。
但是,isSupertypeOf()
仅适用于完全解析的类型,而不完整和原始类不被视为子类型。
package com.common.jsp.beans;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import com.google.common.reflect.TypeToken;
public class TestTypeInf
{
public static class MyCollection1 extends ArrayList<Integer> {
}
public static class MyCollection2 extends ArrayList<Timestamp> {
}
public static class MyCollection3<T> extends ArrayList<T> {
}
public static class MyCollection4 extends ArrayList {
}
public static Collection<Timestamp> fld;
public static void main( String[] args )
throws Exception
{
// bad: fld = new MyCollection1();
fld = new MyCollection2();
fld = new MyCollection3(); // just a warning
fld = new MyCollection4(); // just a warning
Field getter = TestTypeInf.class.getField( "fld" );
Type memberType = getter.getGenericType();
TypeToken<?> resolved = TypeToken.of( TestTypeInf.class ).resolveType( memberType );
System.out.println( "type of fld: " + resolved );
checkAssignable(resolved, MyCollection1.class);
checkAssignable(resolved, MyCollection2.class);
checkAssignable(resolved, MyCollection3.class); // This should be totally valid
checkAssignable(resolved, MyCollection4.class); // why no?
}
private static void checkAssignable(TypeToken<?> resolved, Class<?> implClass) {
System.out.println( "fld = new " + implClass.getSimpleName() + "()" );
System.out.println( resolved.isSupertypeOf( implClass ) ? "yes" : "no" );
}
}
_
type of fld: java.util.Collection<java.sql.Timestamp>
fld = new MyCollection1()
no
fld = new MyCollection2()
yes
fld = new MyCollection3()
no
fld = new MyCollection4()
no
fld = new ArrayList()
no
解决方案
这很 hacky,但由于您尝试做的事情也相当 hacky(即试图反思性地确定在编译器中引发未经检查的警告的分配),我认为这是合理的:
private static boolean isAssignable(TypeToken<?> resolved, Class<?> implClass) {
return resolved.isSupertypeOf(implClass) || isAnySupertypeAssignable(resolved, implClass);
}
private static boolean isAnySupertypeAssignable(TypeToken<?> resolved, Class<?> implClass) {
return TypeToken.of(implClass).getTypes().stream()
.anyMatch(supertype -> isUncheckedSupertype(resolved, supertype));
}
private static boolean isUncheckedSupertype(TypeToken<?> resolved, TypeToken<?> implTypeToken) {
if (implTypeToken.getType() instanceof ParameterizedType) {
return false; // this prevents assignments of Collection<Integer> to Collection<Timestamp>
}
try {
resolved.getSubtype(implTypeToken.getRawType());
return true;
} catch (IllegalArgumentException ex) {
return false;
}
}
我检查了你的例子,它返回:
fld = new MyCollection1() -> no
fld = new MyCollection2() -> yes
fld = new MyCollection3() -> yes
fld = new MyCollection4() -> yes
fld = new ArrayList() -> yes
推荐阅读
- javascript - Type-GraphQL:使用 @Authorized() 装饰器允许文档所有者和管理员/版主访问
- python-3.x - 在 python 计算器中处理负整数输入的最佳方法是什么?
- python-3.x - 使用字典值在for循环中生成数据框后如何查找数据框?
- java - 如何在 JPA 中修复生成的表中的排序。我们是否有一些没有任何框架的解决方法?
- python - 以下代码中的未知缩进错误
- node.js - Heroku 产生错误 H10 并导致应用程序崩溃
- javascript - javascript iframe 播放视频
- android - ViewPager2 - 如何使用 registerOnPageChangeCallback 检查查看寻呼机项目位置
- html - 如何将粘性 div 定位在屏幕右侧?
- python - Django:使用来自 url 的 ForeignKey 创建对象