<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Diego Núñez Silva</title>
    <description>The latest articles on DEV Community by Diego Núñez Silva (@silvermx).</description>
    <link>https://dev.to/silvermx</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F251970%2F615c7306-bc16-4d22-a5e1-4a8a0d16f81c.jpeg</url>
      <title>DEV Community: Diego Núñez Silva</title>
      <link>https://dev.to/silvermx</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/silvermx"/>
    <language>en</language>
    <item>
      <title>Self-validated Java Objects</title>
      <dc:creator>Diego Núñez Silva</dc:creator>
      <pubDate>Fri, 20 Oct 2023 14:58:54 +0000</pubDate>
      <link>https://dev.to/silvermx/self-validated-java-objects-4cdf</link>
      <guid>https://dev.to/silvermx/self-validated-java-objects-4cdf</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;In Java there are several categories for objects whose function is to contain data, &lt;em&gt;e.g.&lt;/em&gt; &lt;a href="https://www.baeldung.com/java-pojo-javabeans-dto-vo"&gt;POJO, Java Bean, DTO, VO&lt;/a&gt;, entities, etc... They differ in some way, but their function is to carry data. For simplicity let's refer to them as Java objects. &lt;/p&gt;

&lt;p&gt;In my experience, these classes/objects tend to be treated as second-class citizens because their function is simply to hold data, and no interesting stuff is included in them.&lt;/p&gt;

&lt;p&gt;Further, developers often neglect unit-testing (serialization, deserialization, equals, etc...) of such classes/objects, but still, bugs can be introduced when their state is not properly validated. So, I tried to find a way of validating such objects while keeping the following goals in mind:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Keep the validation rules inside the class to avoid spreading the domain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid polluting the class with too much validation code for readability purposes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make the validation process compatible with the use of Lombok annotations or Java records.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keep "compatibility" with Spring, so the validation method can be used in the same way as Spring's &lt;code&gt;@Valid&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;The best solution I have found is inspired on &lt;a href="https://youtu.be/cPH5AiqLQTo?t=2127"&gt;Tom Hombergs' idea&lt;/a&gt; and consists of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Using of &lt;a href="https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#section-builtin-constraints"&gt;Jakarta validations + Hibernate validator&lt;/a&gt; as a base to validate the beans.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implementing a &lt;a href="https://github.com/silver-mx/self-validated-beans/blob/main/src/main/java/com/dns/validator/SelfValidated.java"&gt;&lt;code&gt;SelfValidated&lt;/code&gt;&lt;/a&gt; interface that will add a class the ability to exercise all its Jakarta annotations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the complete code in &lt;a href="https://github.com/silver-mx/self-validated-beans/tree/main"&gt;Github&lt;/a&gt; ...&lt;/p&gt;

&lt;h3&gt;
  
  
  Interface &lt;code&gt;SelfValidated&lt;/code&gt; (&lt;a href="https://github.com/silver-mx/self-validated-beans/blob/main/src/main/java/com/dns/validator/SelfValidated.java"&gt;code&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;By making the &lt;a href="https://docs.jboss.org/hibernate/validator/8.0/reference/en-US/html_single/#validator-gettingstarted"&gt;Hibernate &lt;code&gt;Validator&lt;/code&gt;&lt;/a&gt; instance static we ensure that a single instance will be created. A &lt;code&gt;Validator&lt;/code&gt; is thread-safe and can be reused by all classes that implement &lt;code&gt;SelfValidated&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * This interface allows a bean to exercise all the jakarta validations defined. All beans need to implement this interface,
 * and call validate() in order to be validated.
 */&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;SelfValidated&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="cm"&gt;/* NOTE: ValidatorFactory should be closed when the VM is shutting down (see App.java) */&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ValidatorFactory&lt;/span&gt; &lt;span class="n"&gt;validatorFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Validation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buildDefaultValidatorFactory&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Validator&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validatorFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValidator&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;


    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ConstraintViolation&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SelfValidated&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;violations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;violations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ConstraintViolationException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;violations&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Java POJO Example + Lombok &lt;code&gt;@Builder&lt;/code&gt; (&lt;a href="https://github.com/silver-mx/self-validated-beans/blob/main/src/main/java/com/dns/validator/UserPojo.java"&gt;code&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;In the code below, the call to &lt;code&gt;validate()&lt;/code&gt; could be moved to &lt;code&gt;Builder&lt;/code&gt;'s &lt;code&gt;build()&lt;/code&gt; method, but I think a good convention would be to place it always in a constructor, as it will ensure that no instance will be created with an invalid state.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/silver-mx/self-validated-beans/blob/main/src/test/java/com/dns/validator/UserPojoTest.java"&gt;unit-test&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Value&lt;/span&gt;
&lt;span class="nd"&gt;@Builder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builderClassName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Builder"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;setterPrefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"with"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@JsonDeserialize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserPojo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserPojo&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;SelfValidated&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
    &lt;span class="nd"&gt;@Size&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
    &lt;span class="nd"&gt;@Size&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;UserPojo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Java Record (&lt;a href="https://github.com/silver-mx/self-validated-beans/blob/main/src/main/java/com/dns/validator/UserRecord.java"&gt;code&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Here we follow the same convention and make the call to &lt;code&gt;validate()&lt;/code&gt; inside the constructor.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/silver-mx/self-validated-beans/blob/main/src/test/java/com/dns/validator/UserRecordTest.java"&gt;unit-test&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;UserRecord&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
        &lt;span class="nd"&gt;@Size&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
        &lt;span class="nd"&gt;@Size&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
        &lt;span class="nd"&gt;@Email&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;SelfValidated&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UserRecord&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Spring Controller Example (&lt;a href="https://github.com/silver-mx/self-validated-beans/blob/main/src/main/java/com/dns/validator/controller/UserController.java"&gt;code&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;In the snippet below, &lt;code&gt;@Valid&lt;/code&gt; is not actually necessary (left as documentation) because the instance will not even be created if the state is invalid. This means that Spring will not be the one executing the validation. Consequently, we need &lt;a href="https://github.com/silver-mx/self-validated-beans/blob/main/src/main/java/com/dns/validator/controller/RestErrorHandler.java"&gt;&lt;code&gt;RestErrorHandler&lt;/code&gt;&lt;/a&gt; to tell Spring how do we want to handle the exception thrown by &lt;code&gt;validate()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/silver-mx/self-validated-beans/blob/main/src/test/java/com/dns/validator/controller/UserControllerTest.java"&gt;unit-test&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/v1/test"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user-pojo"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserPojo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createUserPojo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nd"&gt;@Valid&lt;/span&gt; &lt;span class="nc"&gt;UserPojo&lt;/span&gt; &lt;span class="n"&gt;userPojo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userPojo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;From the original goals, I see:&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A guarantee that each object will have a valid state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The beans encapsulate their validation rules so it is clear what a valid state is.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;IMHO, the use of Jakarta validations makes the code very readable and it does not feel polluted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Throwing &lt;code&gt;ConstraintViolationException&lt;/code&gt; allows the catcher to identify violations detected in the bean. This works OK with Spring, but it changes a bit the usual behavior if compared with the use of &lt;code&gt;@Valid&lt;/code&gt; + &lt;code&gt;@RequestBody&lt;/code&gt;. It this case, the exception is different and it will be thrown even if &lt;code&gt;@Valid&lt;/code&gt; is not given.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;By adding intelligence to the bean we add a reason to create unit test to verify that everything works as expected.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Disadvantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The approach works for immutable beans. For mutable ones, the method &lt;code&gt;validate()&lt;/code&gt; needs to be called from outside the class, and that could be easily missed. A reason more to prefer immutability.&lt;/li&gt;
&lt;li&gt;The beans suddenly take more importance and maintenance as they now include business logic, when traditionally they have been plain boring objects. This could lead to an overly strict/constrained use of such Java objects.&lt;/li&gt;
&lt;li&gt;The use of Jakarta validations + Hibernate validator has a performance penalty. I tested creating  &lt;strong&gt;100 instances&lt;/strong&gt; of &lt;code&gt;UserPojo.java&lt;/code&gt; with and without validation and I got &lt;code&gt;with=~115ms&lt;/code&gt;, and &lt;code&gt;without=~5ms&lt;/code&gt;. These numbers were measured in a light Intel i5 laptop, but it gives an idea of the difference. In reality, validating a few objects in a real server it probably will not be noticeable, but it is good to keep it in mind.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Feedback
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Please let me know if you see any improvement, or have in general an opinion about the use of validations inside Java objects. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thanks for reading!!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Image credits: &lt;a href="https://tinyurl.com/yfmxsydb"&gt;Self-validated Java beans - Bing Image Creator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>validation</category>
      <category>jakartavalidations</category>
      <category>selfvalidatedbean</category>
    </item>
  </channel>
</rss>
