Cyc*_*nit 6 java generics reflection lambda java-8
这有点是Java8从类中检索lambda setter的后续工作.
我正在尝试为给定字段获取getter方法
public <T, R> IGetter<T, R> getGetter(Class<T> clazz, Field field) {
Class<R> fieldType = null;
try {
fieldType = (Class<R>) field.getType();
} catch(ClassCastException e) {
error("Attempted to create a mistyped getter for the field " + field + "!");
}
return getGetter(clazz, field.getName(), fieldType);
}
Run Code Online (Sandbox Code Playgroud)
这是基本方法:
public <T, R> IGetter<T, R> getGetter(Class<T> clazz, String fieldName, Class<R> fieldType) {
MethodHandles.Lookup caller = null;
MethodHandle target = null;
MethodType func = null;
try {
caller = MethodHandles.lookup();
MethodType getter = MethodType.methodType(fieldType);
target = caller.findVirtual(clazz, computeGetterName(fieldName), getter);
func = target.type();
} catch (NoSuchMethodException e) {
error("Could not locate a properly named getter \"" + computeGetterName(fieldName) + "\"!");
} catch (IllegalAccessException e) {
error("Could not access \"" + computeGetterName(fieldName) + "\"!");
}
CallSite site = null;
try {
site = LambdaMetafactory.metafactory(
caller,
"get",
MethodType.methodType(IGetter.class),
func.generic(),
target,
func
);
} catch (LambdaConversionException e) {
error("Could not convert the getter \"" + computeGetterName(fieldName) + "\" into a lambda expression!");
}
MethodHandle factory = site.getTarget();
IGetter<T, R> r = null;
try {
r = (IGetter<T, R>) factory.invoke();
} catch (Throwable throwable) {
error("Casting the factory of \"" + computeGetterName(fieldName) + "\" failed!");
}
return r;
}
Run Code Online (Sandbox Code Playgroud)
由于类型不匹配,这不会编译:
IGetter<TestEntity, Long> getter = accessorFactory.getGetter(TestEntity.class, "name", String.class);
Run Code Online (Sandbox Code Playgroud)
但是这会编译:
Field field = TestEntity.class.getDeclaredField("name");
IGetter<TestEntity, Long> getter = accessorFactory.getGetter(TestEntity.class, field);
Run Code Online (Sandbox Code Playgroud)
而且,令我惊讶的是,这确实可以使用上面检索到的getter:
TestEntity testEntity = new TestEntity(1L, "Test");
System.out.println(getter.get(testEntity));
Run Code Online (Sandbox Code Playgroud)
但是,一旦我这样做:
Long value = getter.get(testEntity);
Run Code Online (Sandbox Code Playgroud)
我得到以下异常:
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long
at de.cyclonit.exercise.Main.main(Main.java:26)
Run Code Online (Sandbox Code Playgroud)
有没有办法早点抓住这个?
TestEntity类:
public class TestEntity {
private Long id;
private String name;
public TestEntity(Long id, String name) {
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
}
Run Code Online (Sandbox Code Playgroud)
问题是你的方法
public <T, R> IGetter<T, R> getGetter(Class<T> clazz, Field field) {
Class<R> fieldType = null;
try {
fieldType = (Class<R>) field.getType();
} catch(ClassCastException e) {
error("Attempted to create a mistyped getter for the field " + field + "!");
}
return getGetter(clazz, field.getName(), fieldType);
}
Run Code Online (Sandbox Code Playgroud)
实际上并没有进行检查.您基本上是将Class实例转换为Class无效的类型.泛型类型的变化Class<?>来Class<R>是一个纯粹的编译时的事情,这就是为什么你应该在此时得到一个"未登记"的警告,至少,如果所有的警告被启用.
在运行时进行实际检查的唯一方法是从调用者获取预期的类型:
public <T, R> IGetter<T, R> getGetter(Class<T> clazz, Class<R> fieldType, Field field) {
if(fieldType != field.getType()) {
error("Attempted to create a mistyped getter for the field " + field + "!");
}
return getGetter(clazz, field.getName(), fieldType);
}
Run Code Online (Sandbox Code Playgroud)
当然,它使得该方法接受Field有点无意义.实际上getGetter已经执行了一个需要与getter的返回类型完全匹配的查找,并且你不需要获得字段的类型和getter的返回类型必须匹配.实际上,它会对内部细节产生不必要的依赖.
为什么不简单地注释getter而不是字段......