18

Let's say we have tens of java POJOs which represent my domain, that is, my data in the system which flows as objects between different layers of my system. The system may be a web application, or a simple desktop application. What the domain consists of doesn't really matter.

When designing my system, I am confused where I should put any validation logic. My POJOs ( domain objects ) represent my data, and some of the fields inside of those objects must adhere to certain criteria, but if I put a lot of validation logic inside my setter-methods, then the only way to tell the calling client is to throw an exception. And If I don't want the system to crash, the exception must be a checked exception which must be caught and handled. The consequence of that is that each and every time I create a new object using setter-methods (or even constructors), I have do either re-throw that exception or use try-catch block. It doesn't feel right to be forced to use try-catch on many setter-methods.

So the question is where I should put my validation logic, so that I don't clutter the my code with a lot of boilerplate try-catch blocks and rethrows. The finest JAVA byte eaters are welcome to join the discussion.

I have researched and googled, but not found any specific discussion on this topic, so I waiting with great enthusiasm to get some deeper insight into how things really should be done.

marianosimone
  • 3,366
  • 26
  • 32
Gogi
  • 1,695
  • 4
  • 23
  • 36
  • did you check Java bean validation http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html ? – suman j Apr 14 '15 at 20:27
  • Try using bean validation ([JSR-303](http://beanvalidation.org/1.0/spec/)), as implemented by [`hibernate-validator`](http://hibernate.org/validator/) – beerbajay Apr 14 '15 at 20:28
  • Yes, I have checked those concepts, but I am not asking about particular APIs or methods. I want to understand and reflect on what should be done with the validation of data, and where the validation should be put in order to not clutter the system everywhere with a lot of exceptions and exception handling. – Gogi Apr 15 '15 at 17:44
  • When designing an API, I believe it's best to validate input to your public methods as early as possible - there's no need to store or process input that violates any documented contract. Such violations are considered _programming_ errors and can result in _unchecked_ exceptions, such as `IllegalArgumentException`, `UnsupportedOperationException` or NPE, for example. This prevents the "garbage in - garbage out" scenarios and alerts the caller that they're doing something wrong, _without_ having to clutter the code with exception handling. – fspinnenhirn Apr 15 '15 at 18:55
  • 1
    It can be argued that having such validation logic is the *reason* for having setter methods: http://stackoverflow.com/a/1461662/545127 – Raedwald Apr 16 '15 at 05:40
  • See also http://stackoverflow.com/a/12108025/545127 – Raedwald Apr 16 '15 at 05:44

4 Answers4

16

You might have answered your own question when you said

some of the fields inside of those objects must adhere to certain criteria

It always helps to think about the invariants in your system, i.e. the things you want to maintain at all cost or the rules that must always be followed.
Your POJOs are the "last line of defence" for such invariants on your data objects and thus an appropriate - or even necessary - place to put validation logic. Without such validation, an object might no longer represent something that makes sense in your domain.

These system invariants form a contract between your objects (or methods) and their "clients". If someone is trying to use them contrary to the (hopefully well-documented) contract, throwing an exception is the right thing to do, since it is the client's responsibility to use the individual parts of the system correctly.

Over time, I've started favoring unchecked exceptions over checked ones for any instances of contract violations, partly because of the reason you mention, namely to avoid try-catch blocks everywhere.
Java's standard unchecked exceptions include:

  • NullPointerException
  • IllegalArgumentException
  • IllegalStateException
  • UnsupportedOperationException

A best practice guideline is to use checked exceptions when an error is considered recoverable and unchecked exceptions otherwise.

Chapter 9 of Joshua Bloch's "Effective Java, 2nd ed." provides more wisdom on this topic:

  • Item 57: Use exceptions only for exceptional conditions
  • Item 58: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors
  • Item 59: Avoid unnecessary use of checked exceptions
  • Item 60: Favor the use of standard exceptions

None of the above should deter you from using any appropriate validation logic at higher levels, especially to enforce any context-specific business rules or constraints.

fspinnenhirn
  • 1,784
  • 1
  • 13
  • 27
  • Yes, the POJO must at all times be in a valid state. I did look into the items from the Effective Java but they are little difficult to grasp, I think certainly they will appear difficult to an intermediate who knows the OO-design principles, but cannot decide properly how to apply those items. For example, I don't understand what he means specifically by 'recoverable' and 'programming errors'. Some concrete and probably different examples could help to understand the powerful ideas behind those suggestions. What does he mean by 'unnecessary', do we have any well-known examples of that. – Gogi Apr 15 '15 at 17:52
  • I agree that Bloch requires careful reading and your concerns would be great SO questions on their own. A _programming_ error is something that violates a contract, e.g. passing `null`, or a negative index, when it is documented that this isn't supported. An example for a _recoverable_ error might be something like a timeout, where the caller could decide to retry later or just give up; using a _checked_ exception forces the caller to deal with this and make a decision. Using checked exceptions for flow-control instead of `IF-ELSE` blocks is an example of _unnecessary_ use. – fspinnenhirn Apr 15 '15 at 19:13
3

All in all I also don't don't think there's a unique solution to fit every need, and it just comes down to your scenario and preference.

From an encapsulation point of view, I believe the setter validation is just the right way to go as it's the logical place to decide whether the provided information is correct and offer a detailed explanation on what may be wrong. However I'm not sure what you mean by:

And If I don't want the system to crash, the exception must be a checked exception...

Why would the system crash? Unchecked exceptions can be very well caught like checked ones. You need to figure out how your program should behave when such an event occurs, so you can decide where to catch them and what to do.

Checked vs unchecked has long been, and still is, debated in various ways and beliefs, but I see no reason why you should not throw an unchecked exception. Just make a common ConfigurationException (or use the already present IllegalArgumentException) or whatever floats your boat, mark your method signatures accordingly and add proper java-docs so whoever calls them knows what to expect, and throw it when required.

Depending on you object relations and hierarchy, another solution could be some builders which run you custom validations just when creating the instances. But like I said it really depends on the scenario, and you may not be able to prevent other people from manually instantiating and incorrectly populating some objects.

Morfic
  • 15,178
  • 3
  • 51
  • 61
1

In some situations the solution is to make all setters private and provide a single point of entry for initializing the objects. Then all the validation and exception handling is in that initialization method.
This also ensures that no object can be partially initialized.
Object state change can be handled this way too, by making the object immutable except through a constructor / initialization method, thou this can become wasteful if abused.

Richard
  • 527
  • 3
  • 9
1

While you can put validation logic on bean setter methods, I found that in practice, a clearer separation of concerns would be to move any complex validation to another class specific for validation. Hear me out.

Using bean validation is fine, but in many cases (to which I'm sure you're coming across now), a simple annotation will not carry thorough enough validation. Frameworks like Spring have Validators that you can implement to do this.

There are numerous benefits to separating validation logic:

  • Code re-use. In some cases, the setter validation for one bean may be identical to that of another bean. This also carries forward to more concise unit tests.
  • In many cases, you won't be dealing with exceptions at all, but rather displaying an error message to the user
  • You can log appropriately without filling your POJOs with logging statements or forcing them to implement a logger
  • Code is far more readable and intent is better understood

Hope that helps.

riddle_me_this
  • 8,575
  • 10
  • 55
  • 80
  • Some essential points you are making here, specially logging, readability, and separation of concerns. Can you cook some really "deep" and realistic example which would clear up the smoke a little bit? – Gogi Apr 15 '15 at 17:57
  • If you somehow need a more specific example I can supply one later, but this should suffice: http://www.journaldev.com/2668/spring-mvc-form-validation-example-using-annotation-and-custom-validator-implementation. As you can see, there's no validation in setter methods. This design has been used a long time and in production environments. In case the link is broken later, Googling for example uses of the Spring Validator will give you more cases. – riddle_me_this Apr 15 '15 at 21:22