установка поля в классе исключений и получение с отражением - PullRequest
0 голосов
/ 30 апреля 2020

У меня есть следующая иерархия исключений:

public class C extends B {

    public C(final String message) {
        super(message);
    }
}

public abstract class B extends A {

    public B(final String message, final Throwable throwable) {
        super(message, throwable);
    }

    public B(final String message) {
        super(message);
    }
}

public class A extends RuntimeException {

    private boolean bypassable;

    public A(final String message) {
        super(message);
    }

    public A(final String message, final Throwable throwable) {
        super(message, throwable);
    }

    public boolean isBypassable() {
        return bypassable;
    }

    public void setBypassable(final boolean bypassable) {
        this.bypassable = bypassable;
    }
}

В моем классе рекомендаций по аспектам я ловлю исключение типа A и задаю значение bypassable. Обратите внимание, что я не перехватываю указанное c исключение типа C:

@Aspect
@Component
public class ByPassableExceptionAspect {

    @Around("@annotation(...)")
    public void handle(final ProceedingJoinPoint pjp) throws Throwable {
        try {
            pjp.proceed();
        } catch (A exception) {
            a.setByPassable(true);
            }
        } catch (Throwable t) {
            throw t;
        }
    }
}

Мне нужно сохранить информацию, которую можно перебрасывать, в базу данных как json, поэтому у меня есть этот класс сериализатора:

private class ThrowableJsonSerializer extends JsonSerializer<Throwable> {
    @Override
    public void serialize(final Throwable value,
                          final JsonGenerator gen,
                          final SerializerProvider serializers) throws IOException {
        writeThrowable(someOtherMethod(value), gen);
    }

    private void writeThrowable(final Throwable value,
                                final JsonGenerator gen) throws IOException {
        gen.writeStartObject();
        gen.writeFieldName("class");
        gen.writeString(value.getClass().getName());

        writeBypassableIfExists(value, gen);

        if (nonNull(value.getCause())) {
            gen.writeFieldName("cause");
            writeThrowable(value.getCause(), gen);
        }
        gen.writeEndObject();
    }

    private void writeBypassableIfExists(final Throwable throwable, final JsonGenerator gen) throws IOException {
        final Field bypassableField = ReflectionUtils.findField(throwable.getClass(), "bypassable"); //Spring Framework ReflectionUtils
        if (nonNull(bypassableField)) {
            bypassableField.setAccessible(true);
            gen.writeFieldName("bypassable");
            gen.writeString(String.valueOf(ReflectionUtils.getField(bypassableField, throwable)));
        }
    }
}

У меня проблема с атрибутом bypassable. Хотя в коде аспекта я установил значение true, в базе данных оно сохраняется как ложное.

Я думаю, это потому, что я каждый раз вызываю writeThrowable() с причиной, и как-то подкласс C ссылается на bypassable как ложное. Когда я запускаю в режиме отладки, я получаю bypassable написано дважды.

Я ищу помощь, чтобы правильно написать поле bypassable. Я не уверен, как фильтровать причину, которая имеет true. Возможно, нужно отфильтровать ссылку на суперкласс? Буду признателен за вашу помощь.

Json:

[
  {
    "cause": {
      "cause": {
        "class": "com.exception.C",
        "message": "blah blah",
        "bypassable": "true"
      },
...
...