我有以下两种方法:
public static <T, R> IGetter<T, R> createGetterViaMethodname( final Class<T> clazz, final String methodName,
final Class<R> fieldType )
throws Throwable
{
final MethodHandles.Lookup caller = MethodHandles.lookup();
final MethodType methodType = MethodType.methodType( fieldType );
final MethodHandle target = caller.findVirtual( clazz, methodName, methodType );
final MethodType type = target.type();
final CallSite site = LambdaMetafactory.metafactory(
caller,
"get",
MethodType.methodType( IGetter.class ),
type.erase(),
target,
type );
final MethodHandle factory = site.getTarget();
return (IGetter<T, R>) factory.invoke();
}
public static <T, I> ISetter<T, I> createSetterViaMethodname( final Class<T> clazz, final String methodName,
final Class<I> fieldType )
throws Throwable
{
final MethodHandles.Lookup caller = MethodHandles.lookup();
final MethodType methodType = MethodType.methodType( void.class, fieldType );
final MethodHandle target = caller.findVirtual( clazz, methodName, methodType );
final MethodType type = target.type();
final CallSite site = LambdaMetafactory.metafactory(
caller,
"set",
MethodType.methodType( ISetter.class ),
type.erase(),
target,
type );
final MethodHandle factory = site.getTarget();
return (ISetter<T, I>) factory.invoke();
}
包括以下两个接口:
@FunctionalInterface
public interface IGetter<T, R>
{
@Nullable
R get( T object );
}
@FunctionalInterface
public interface ISetter<T, I>
{
void set( T object, @Nullable I value );
}
这适用于所有类类型,包括基本类型的数字 Package 器,例如 Integer
对于 int
. 然而,如果我有一个二传手 int
或者返回 ìnt
,它尝试传递/返回数字 Package ,导致异常。
在不必使用其他方法的情况下,装箱/取消装箱的正确方法是什么。这里的原因是为了保持api干净且易于使用。我愿意在这里为拳击/拆箱表演一次小小的打击。
2条答案
按热度按时间5t7ly7z51#
没有内置的“漂亮”方法将基本类转换为 Package 类,因此必须使用如下Map:
或者在这里使用其他方法之一。
一旦你这么做了,你可以检查一下
fieldType
是原始的。如果是,请通过在Map中查找 Package 器类型来更改方法类型的返回类型/参数类型。对于getter:
对于setter:
如果不清楚,调用方将传递原语getter和setter的原语类:
完整代码:
dauxcl2d2#
另一种方法是使用外部库而不是lambdametafactory。cojen/maker库提供对代码生成的直接控制,并自动执行装箱/拆箱转换。
即使字段类型为int,此示例也可以正常工作。调用方必须直接提供lookup类才能访问任何非公共方法,但在原始示例中这也是必需的。这意味着
<T>
未使用param,但此示例应该足够了。