[英]Printing debug info on errors with java 8 lambda expressions
我想使用静态方法作为 setter helper 来捕获异常并打印有关失败操作的调试信息。 我不只想要异常详细信息。 我想显示正在设置的属性,以便详细信息有助于快速调试问题。 我正在使用 Java 8。
我应该如何提供或检测正在设置的属性?
我希望删除示例中的“名称”字符串并获得相同的结果。
我知道我不能对所提供的 setter 方法使用反射,该方法被转换为 lambda 表达式,然后转换为 BiConsumer。
我得到了这个,但需要提供属性名称。
/** setter helper method **/
private static <E, V> void set(E o, BiConsumer<E, V> setter,
Supplier<V> valueSupplier, String propertyName) {
try {
setter.accept(o, valueSupplier.get());
} catch (RuntimeException e) {
throw new RuntimeException("Failed to set the value of " + propertyName, e);
}
}
例子:
Person p = new Person();
Supplier<String> nameSupplier1 = () -> "MyName";
Supplier<String> nameSupplier2 = () -> { throw new RuntimeException(); };
set(p, Person::setName, nameSupplier1, "name");
System.out.println(p.getName()); // prints MyName
set(p, Person::setName, nameSupplier2, "name"); // throws exception with message Failed to set the value of name
System.out.println(p.getName()); // Does not execute
编辑:我知道反射对 lambdas 没有帮助。 我知道 AOP 并且我知道这也可以通过纯反射来实现,但我想知道是否有更好的方法来完成 Java 8 中不存在的 Java 7。对我来说似乎应该这样做。 现在可以做一些事情,比如将 setter 方法传递给另一个方法。
如果您希望方法引用作为唯一的输入,您可以使用以下技巧将它们调试为可打印的名称:
public static void main(String[] args) {
Person p = new Person();
Supplier<String> nameSupplier1 = () -> "MyName";
Supplier<String> nameSupplier2 = () -> { throw new RuntimeException(); };
set(p, Person::setName, nameSupplier1);
System.out.println(p.getName()); // prints MyName
set(p, Person::setName, nameSupplier2); // throws exception with message
System.out.println(p.getName()); // Does not execute
}
interface DebuggableBiConsumer<A, B> extends BiConsumer<A, B>, Serializable {}
private static <E, V> void set(
E o, DebuggableBiConsumer<E, V> setter, Supplier<V> valueSupplier) {
try {
setter.accept(o, valueSupplier.get());
} catch (RuntimeException e) {
throw new RuntimeException("Failed to set the value of "+name(setter), e);
}
}
private static String name(DebuggableBiConsumer<?, ?> setter) {
for (Class<?> cl = setter.getClass(); cl != null; cl = cl.getSuperclass()) {
try {
Method m = cl.getDeclaredMethod("writeReplace");
m.setAccessible(true);
Object replacement = m.invoke(setter);
if(!(replacement instanceof SerializedLambda))
break;// custom interface implementation
SerializedLambda l = (SerializedLambda) replacement;
return l.getImplClass() + "::" + l.getImplMethodName();
}
catch (NoSuchMethodException e) {}
catch (IllegalAccessException | InvocationTargetException e) {
break;
}
}
return "unknown property";
}
限制是它不会为 lambda 表达式打印非常有用的方法引用(对包含 lambda 代码的合成方法的引用)和接口的自定义实现的"unknown property"
。
那个怎么样?
源代码:
package test;
import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.Function;
public class Person {
public String getName() {
return "Michael";
}
public static void main(String[] args) throws
NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Serializable s = (Function<Person, String> & Serializable) Person::getName;
Method method = s.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(true);
SerializedLambda serializedLambda = (SerializedLambda) method.invoke(s);
System.out.println(serializedLambda.getImplClass().replace("/", ".")
+ "::" + serializedLambda.getImplMethodName());
}
}
输出:
test.Person::getName
您实际上需要查找方法“writeReplace”,调用它并评估其类型为 SerializedLambda 的返回值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.