Impression d'informations de débogage sur les erreurs avec des expressions java 8 lambda


Je veux utiliser une méthode statique en tant qu'assistant setter qui intercepte les exceptions et affiche les informations de débogage sur l'opération qui a échoué. Je ne veux pas seulement les détails de l'exception. Je veux montrer quelle propriété était définie afin que les détails aident à déboguer le problème rapidement. Je travaille avec Java 8.

Comment dois-je fournir ou détecter la propriété en cours de définition?

Ce que je souhaite, c'est supprimer la chaîne "name" dans l'exemple et obtenir le même résultat.

Je sais que je ne peux pas utilisez la réflexion sur la méthode setter fournie fournie qui est transformée en expression lambda, puis en BiConsumer.

J'ai obtenu ceci mais le nom de la propriété doit être fourni.

/** 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);
    }
}

Exemple:

    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

EDIT: Je sais que la réflexion n'aide pas avec les lambdas. Je connais AOP et je sais que cela peut aussi être fait avec une réflexion pure, mais je veux savoir s'il existe un meilleur moyen de le faire avec Java 8 qui n'existait pas avec Java 7. Il semble qu'il devrait pour moi. Maintenant, il est possible de faire des choses comme passer une méthode setter à une autre.

Author: aalku, 2014-02-18

1 answers

Si vous attendez des références de méthode comme seule entrée, vous pouvez les déboguer en noms imprimables avec l'astuce suivante:

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";
}

Les limitations sont qu'il imprimera des références de méthode peu utiles pour les expressions lambda (références à la méthode synthétique contenant le code lambda) et "unknown property" pour les implémentations personnalisées de l'interface.

 18
Author: Holger, 2014-02-19 11:23:27