My requirement is that the user will see localized messages at the end of the process. If the process failed, there will be at least one "external" message of type error. If the process was successfully executed, the user might see multiple "external" information messages.
Additionally, all messages (including internal) shall be logged by the application.
Now here comes the tricky part. Assume the following callstack:
- controller.uploadImageHandler
- imageService.createImageContainer
- galleryService.loadForImage
- galleryService.validateGalleryAttributes
Now validateGalleryAttributes
will validate 3 attributes. 2 aren't matching, so the messages Attribute A must be X
and Attribute B must not be empty
of type External
are generated and logged to the application log. The calls before added multiple information messages.
Now I need have to
- abort processing
- bubble the Messages up
Is the right approach to pass along a Message Collection (or add a collection to the logger) into every method, throw an Exception upon failure (even simple ones such as invalid attributes), extract the messages at the controller level and return them to the user? It's not enough to add them to the exception class, since info messages must also be possible and multiple methods might produce just messages.
But honestly it seems a bit weird to have a collection that is inspected upon success and exception. Is there a better language construct?
CodePudding user response:
Theres two alternative solutions that I could come up with.
If you are into monads at all you could move away from using exceptions to a custom
LoggingEither<L, R>
orLoggingResult<S, E>
return type. They would carry the result/exception as well as all accumulated messages so far. You would just have to make sure to merge the messages of all methods you call into the object you return in the current method. For an idea of how these monad types could be implemented take a look at vavr.If everything happens in the same Thread you could consider using ThreadLocal to keep track of all the log messages. This eliminates the need of passing a collection down the stacktrace. You will still need to take care of bundling messages and resetting the
ThreadLocal
, though.