Records -- Using them as JPA entities and validating them with Bean Validation

Gunnar Morling gunnar at hibernate.org
Wed Apr 11 17:06:34 UTC 2018


2018-04-10 17:13 GMT+02:00 Brian Goetz <brian.goetz at oracle.com>:

>
>
>> Does JPA rely on runtime-generated proxies?  If so, what does the proxy
>> inject into the class?  (In any case, for proxies, finality is a problem.)
>
>
> Yes, indeed proxies are used in some cases. E.g. when an entity is
> configured to lazy-load specific properties, JPA would return a proxy for
> the entity, which contains the logic to lazily fetch the property value
> upon first invocation of someEntity.someLazyProp().
>
>
> This is the high-order bit; if we can't address this then the rest don't
> matter.
>
  Are there concrete criteria that we can use to reason about when it would
> try to create a proxy?
>

One criteria is whether there are lazily loaded references to entities.
E.g. consider this model:

    @Entity
    public class Book {

        @Id private long id;
        private String title;
        @OneToOne(fetch=FetchType.LAZY) private Author author;

        // getters, setters ...
    }

    @Entity
    public class Author {

        @Id private long id;
        private String name;

        // getters, setters ...
    }

Now when getting a Book from the entity manager, the "author" reference
will contain a proxy:

    book = entityManager.find( Book.class, 1L );

Only when accessing non-id properties from the author, the proxy will
trigger the load of the Author data from the database:

    authorName = book.getAuthor().getName();

Another usage of proxies within Hibernate's JPA implementation is the
load() API which wraps the provided PK in a proxy without hitting the DB
(which e.g. is useful for establishing associations between entities
without loading all of them):

    authorProxy = session.load( Author.class, 1L );
    book.author = authorProxy;

There might be other usages of proxies which I'm not aware of.


> What if the domain class is final?
>

Any lazy loading will automatically be disabled; E.g. when retrieving a
Book, the associated Author would be loaded from the DB at the same time.
I.e. you'd typically end up with more accesses to the DB then desired,
resulting in a degraded performance of the application.

> For JPA, some control would be needed to decide between field or getter
> (the location of the @Id annotation determines the default access strategy
> to be used by the JPA provider, and a user may wish to use one or the
> other).
>
>
> Its pretty important that there be no control knobs.  (The first is the
> most dangerous; once you have one, you will soon have many.)
>
>
>   The only justifiable path I can envision would be to map to all of them
>> that would be permitted by the @Target of the annotation, which might or
>> might not work for your cases.
>>
>
> That wouldn't really work well for the JPA use case, as we'd end up with
> the annotations on fields *and* getters, which is at least confusing (not
> sure out of my head whether it's not even considered illegal).
>
>
> I have to assume that if a framework sees it on both, it will (or can)
> make a choice about which it finds preferable?
>

Yes, indeed Hibernate ORM will choose one of them in this case. It's not a
mapping a user would typically use themselves, but this shouldn't matter
here.

For Bean Validation, things are a bit worse. The spec is very clear about
the fact that a constraint annotation should only be put to a field *or*
the corresponding getter, as otherwise both constraints would be checked
when validating an instance of the type hosting the field and getter.

We could work around that if there was a way to find out whether a given
annotation was derived from a record's state elements, in which case we
e.g. could decide to ignore them on fields and just apply them on getters.

> One more thing I'm realizing now is that the proposal is to name generated
> read accessors fieldName() instead of getFieldName(). The latter is
> expected by JPA (currently at least, it might evolve of course).
>
>
> Surely this could evolve.
>

Yes; while specific JPA providers (such as Hibernate) might adopt such
naming pattern more quickly, it remains to be seen whether/when it would be
adopted at the spec level.

> So overall, as things stand, it appears to me as if it wouldn't really be
> beneficial to use records as JPA entities.
>
>
> I think the finality is the real question here -- so let's discuss that.
>

Agreed. But I also think the question of custom equals()/hashCode() methods
is important.


More information about the amber-dev mailing list