jeudi 30 avril 2020

persisting exception class property as json with subclass and superclass

I have the following exception Hierarchy:

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

In my aspect advice class I am catching exception of type A and setting the bypassable value. Please note I am not catching the specific exception of type 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;
        }
    }
}

I need to persist the throwable information into database as json so I have this serializer class:

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

The issue I have is with the bypassable attribute. Although I set the value as true in my aspect code, it gets persisted as false in the database.

I think it is because I am calling writeThrowable() with cause each time and somehow the subclass C has reference to bypassable as false. When I run in debug, I get bypassable is written twice.

I am looking for some help to write bypassable field correctly. I am not sure how to filter on the Cause that has true. Perhaps need to filter on the superclass reference one? Would appreciate your help.

Json:

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




Aucun commentaire:

Enregistrer un commentaire