se.fortnox.reactivewizard.util.MethodSetter Maven / Gradle / Ivy
package se.fortnox.reactivewizard.util;
import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.function.BiConsumer;
/**
* Represents a setter method.
*/
public class MethodSetter implements Setter {
public static Setter create(Class cls, Method method) {
AccessorUtil.MemberTypeInfo memberTypeInfo = AccessorUtil.setterTypeInfo(cls, method);
return new MethodSetter<>(method, memberTypeInfo.getReturnType(), memberTypeInfo.getGenericReturnType());
}
private final BiConsumer setterLambda;
private final Class> parameterType;
private final Type genericParameterType;
private MethodSetter(Method method, Class parameterType, Type genericParameterType) {
this.parameterType = parameterType;
this.genericParameterType = genericParameterType;
MethodHandles.Lookup lookup = ReflectionUtil.lookupFor(method.getDeclaringClass(), method);
try {
MethodHandle methodHandle = lookup.unreflect(method);
setterLambda = compileLambda(lookup, methodHandle);
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
private BiConsumer compileLambda(MethodHandles.Lookup lookup, MethodHandle methodHandle) throws Throwable {
CallSite callSite = LambdaMetafactory.metafactory(
lookup,
"accept",
MethodType.methodType(BiConsumer.class),
MethodType.methodType(void.class, Object.class, Object.class),
methodHandle,
wrapMethodType(methodHandle.type())
);
return (BiConsumer) callSite.getTarget().invoke();
}
private MethodType wrapMethodType(MethodType methodType) {
// JDK9+ has made changes to LambdaMetaFactory that prevent lambdas from being able to do proper
// adaptation of types. In particular boxed types are no longer widened appropriately and
// Object can no longer be adapted to primitive types.
return methodType.wrap().changeReturnType(void.class);
}
@Override
public void invoke(I instance, T value) {
setterLambda.accept(instance, value);
}
@Override
public Class> getParameterType() {
return parameterType;
}
@Override
public Type getGenericParameterType() {
return genericParameterType;
}
@Override
public BiConsumer setterFunction() {
return setterLambda;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy