Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>First, let me address the "drawbacks" you've listed to your first approach:</p> <blockquote> <p>You're starting to implement code that depends on the client (Hibernate). Ideally, a class does not know its callers.</p> </blockquote> <p>You're using the word "dependency" a bit fast and loose here. Hibernate is not a "client"; it's a framework <strong>you</strong> (as developer / architect / what have you) chose to implement your persistence with. Therefore, you're going to have some code somewhere that uses (and, thus, depends on) Hibernate. That said, there is <strong>NO</strong> dependency on Hibernate in your domain object above. Having a no-arg constructor is a semantic requirement if you will; it does not introduce an actual dependency. Switch Hibernate for JPA / TopLink / raw jdbc / what have you and you won't have to change a single thing in your domain object code.</p> <blockquote> <p>A specific issue with this workaround is that instances initiated by hibernate are not checked if the meet the invariants. You're trusting data that is loaded from the database which is problematic. Even if your application is the only one using this specific database schema there is always the possibility of ad-hoc changes by administrators.</p> </blockquote> <p>You <strong>don't have to "trust"</strong> the data (more on that below). However, I don't think this argument has merit. If you're modifying your data in multiple applications, you should be performing validations at some common lower layer instead of relying on each individual application to validate the data. Said common layer could be the database itself (in simple cases) or a service layer providing common API to be used by your multiple applications.</p> <p>Furthermore, the notion of administrators making changes <strong>directly</strong> to the database as part of <strong>daily routine</strong> is utterly ridiculous. If you're talking about special cases (bug fixes, what have you) they should be treated as such (that is, presumably something like this happens very rarely and the burden to validate such "critical" changes lies on whoever makes the changes; not on each of your applications in the stack).</p> <p>All that said, if you do want to validate your object when they're <strong>loaded</strong>, it's reasonably straightforward to achieve. Define a <code>Valid</code> interface that has <code>validate()</code> method and have every concerned domain object implement it. You can invoke that method from:</p> <ol> <li>Your DAO / service after the object has been loaded.</li> <li><a href="http://docs.jboss.org/hibernate/stable/core/reference/en/html/events.html" rel="nofollow noreferrer">Hibernate Interceptor or Listener</a> - both are set up in Hibernate configuration; all you need to do is to implement either one to check whether the object being loaded implements <code>Valid</code> and, if so, invoke the method.</li> <li>Or you can use <a href="http://docs.jboss.org/hibernate/stable/validator/reference/en/html/" rel="nofollow noreferrer">Hibernate Validator</a>, however that WILL tie your domain objects to Hibernate as you'd be annotating them.</li> </ol> <p>Finally, as far as "constructor injection" goes - I do not know of any framework that supports it <strong>directly</strong>. The reason for this is quite simple - it only makes sense for <strong>immutable</strong> entities (because once you have setters you have to deal with validation anyway) and thus means a lot of work (handling constructor parameter mappings, etc...) for almost zero net effect. In fact, if you're <strong>that</strong> concerned with having a no-arg constructor for immutable objects you can always not map them as entities and instead load them via HQL which <strong>does</strong> support <a href="http://docs.jboss.org/hibernate/stable/core/reference/en/html/queryhql.html#queryhql-select" rel="nofollow noreferrer">constructor injection</a>:</p> <pre><code>select new A(x, y) from ... </code></pre> <p><strong>Update</strong> (to address points from Thomas's comments):</p> <ol> <li>I've only mentioned the interceptor for completeness; listener is much more appropriate in this case. <a href="http://docs.jboss.org/hibernate/stable/core/api/org/hibernate/event/PostLoadEventListener.html" rel="nofollow noreferrer">PostLoadEventListener</a> is called after entity is fully initialized.</li> <li>Once again, having no-arg constructor is not a dependency. It's a contract, yes, but it it doesn't tie your code to Hibernate in any way. And as far as contracts go, it's a part of javabean spec (in fact, it's less restrictive because constructor doesn't have to be public) so in majority of cases you would follow it anyway.</li> <li>Accessing the database. "Database refactoring and migrations are common" - yes, they are. But it's just code; you write it, you test it, you run the integration tests, you deploy it to production. If your domain model object uses some <code>StringUtil.compare()</code> method you wrote in some utility class, you don't have it recheck the results, do you? Similarly, domain object should not have to check that your migration script didn't break anything - you should have appropriate tests for that. "Ability to do ad-hoc queries ... is one of the features" - absolutely. <strong>Queries</strong>. As in "read-only" queries used for reporting, for example (even so, in many cases it's more appropriate to go through the API). But manual data <strong>manipulation</strong> as non-emergency - absolutely not.</li> <li>Mutability makes constructor injection <strong>irrelevant</strong>. I'm not saying you can't have non-default constructor - you can, and you can use it in your code. But if you have setter methods you can not use your constructor for validation, so whether it is or isn't there doesn't really matter.</li> <li>HQL constructor injection and associations. <strong>Nested</strong> constructors won't work as far as I know (e.g. you can't write <code>select new A(x, y, new B(c, d))</code>; so in order to fetch associations you're going to need to retrieve them as entities in select clause which means they need to have no-arg constructors themselves :-) Or you can have a constructor on "main" entity that takes all needed nested properties as arguments and constructs/populates associations internally but that's borderline crazy :-)</li> </ol>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload