Win a copy of Rust Web Development this week in the Other Languages forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Tim Cooke
  • Campbell Ritchie
  • Ron McLeod
  • Liutauras Vilda
  • Jeanne Boyarsky
Sheriffs:
  • Junilu Lacar
  • Rob Spoor
  • Paul Clapham
Saloon Keepers:
  • Tim Holloway
  • Tim Moores
  • Jesse Silverman
  • Stephan van Hulst
  • Carey Brown
Bartenders:
  • Al Hobbs
  • Piet Souris
  • Frits Walraven

Exception Translation

 
Ranch Hand
Posts: 2198
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi!
I have an application service that receives certain exceptions from the domain layer and possibly underlying layers.
I would like to translate received exceptions to application-specific exceptions, but would prefer to separate the code that performs the translation, so that it does not make the code in the service class more difficult to understand.
Is there a way to accomplish this in Scala?
Thanks in advance!
 
Ivan Krizsan
Ranch Hand
Posts: 2198
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi!
As at some previous occasions, I will answer my own question. I will do it with an example that uses pure Scala.
In this very simplistic example, there is one domain class that is used by an application service. In addition there is a client of the service.
The domain class is written to throw different kinds of generic exceptions:


Then there is the application service class that calls the above domain class.

As you can see, the service class do not contain any exception handling or translation. This is the goal of this exercise - I do not want to clutter the service class, containing application logic, with error handing, logging, exception translation etc. Despite this, I want the service to throw application-specific exceptions to clients in case of errors.

As an interlude and in order to make the example complete, here are the classes implementing the application-specific exceptions:




Then there is a client of the application service, which also is the starter class of this example:


If we run the example program in its current incarnation, we obtain the following output:


Trying with a message that is too short
Unexpectedly received another exception :java.lang.IllegalArgumentException
Trying with a number that is too small (negative)
Unexpectedly received another exception :java.lang.IllegalArgumentException
Trying with a number that breaks an assumption
Unexpectedly received another exception :java.lang.AssertionError
Trying with good parameters, which should result in an exception that should be passed through
Received IOException as expected: cannot read data



In three of the four cases, the client received an exception that I did not want it to receive.
So, how do we fix this without adding code to the service class and use only pure Scala?
The solution I have devised uses traits. I separate all the exception translation code into the following trait:


To bring the above trait together with the service class, I implement a child class to the service class:


Finally, we modify the client to instantiate the child service class instead of the original service class. Note also that I have uncommented one import:


If we now run the example program, we get the following output:


Trying with a message that is too short
Received a MessageTooShortException as expected: The message 'a' is too short
Trying with a number that is too small (negative)
Received a NumberTooSmallException as expected: The number '-1' is too small
Trying with a number that breaks an assumption
Received a AssumptionBrokenException as expected: Assumption broken: assumption failed: the result of doubling the number must not become 4
Trying with good parameters, which should result in an exception that should be passed through
Received IOException as expected: cannot read data



I succeeded in separating application logic, in the application service, and exception translation!
There is more, but interested readers need to wait for my next book to read about the details.
Best wishes!
 
Bartender
Posts: 2407
36
Scala Python Oracle Postgres Database Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for sharing your solution, Ivan. Many of us around here are only just starting to learn Scala, so it's always good to see how other people solve problems like this.
 
Ivan Krizsan
Ranch Hand
Posts: 2198
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi again!
I have further improved the solution I earlier posted. Changes are:
  • Introduce a trait as interface of the service.
  • Remove the service child class that mixed in the trait(s) implementing non-business concerns.
  • Perform mixin of the trait(s) implementing non-business concerns at service instance creation time.
  • Eliminated the MyApplicationServiceExceptionHandling trait.
  • Eliminated the class MyApplicationServiceWithExceptionTranslation.
  • Added a trait to perform logging (non-business concern).


  • Code speaks louder than words, so here is the modified example program. The domain and exception classes are the same as in the above post, so please refer to that post for implementation of those classes.










    Note that the order in which the traits are mixed in is significant. Try experimenting with the logging trait first and look at the exceptions logged.
    I feel that this new solution is more elegant than the previous one. One possible drawback may be that it will be difficult to re-use traits implementing non-business concerns with different services.
    Best wishes!
     
    You showed up just in time for the waffles! And this tiny ad:
    Building a Better World in your Backyard by Paul Wheaton and Shawn Klassen-Koop
    https://coderanch.com/wiki/718759/books/Building-World-Backyard-Paul-Wheaton
    reply
      Bookmark Topic Watch Topic
    • New Topic