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