[hibernate-dev] [feature request][discuss] smoother serializers integration?
Christian Beikov
christian.beikov at gmail.com
Thu May 4 06:03:59 EDT 2017
This is exactly what I am trying to do with Blaze-Persistence Entity
Views, making DTOs sexy and efficient :)
Here a quick overview of how that looks like right now:
https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#first-entity-view-query
One of my targets is to make it possible to do something like this
entityManager.createQuery("FROM Order o", OrderDTO.class).getResultList()
and get an optimal query, as well as objects with only the necessary
contents.
Maybe we can collaborate on that somehow?
Mit freundlichen Grüßen,
------------------------------------------------------------------------
*Christian Beikov*
Am 04.05.2017 um 10:20 schrieb Emmanuel Bernard:
> Following up a bit on my previous email.
>
> While a core integration might be best I think, if there are too much
> reluctance, we can start with a dedicated hibernate-dto or whatever
> module or even separate project that makes life easier for these "pass
> through" use cases. This could be in the form of a wrapper API of sort
> and hence not affect existing Hibernate ORM APIs.
>
> Note that the ResultTransformer approach feels like it goes a long way
> towards fixing the problem but as demonstrated in Vlad's article
> https://vladmihalcea.com/2017/04/03/why-you-should-use-the-hibernate-resulttransformer-to-customize-result-set-mappings/
> it still requires quite a bit of code and a special DTO constructor
> object. That's what we need to get rid of I think.
>
> Emmanuel
>
> On Thu 17-05-04 10:04, Emmanuel Bernard wrote:
>> I was very much in the Vlad, Steve, Christian camp until relatively
>> recently. One of my main concern being that replacing a proxy by null
>> was really sending the wrong message. So I was against having Hibernate
>> ORM facilitate such a transformation.
>>
>> I am changing my mind because I am realizing that a lot of applications
>> are less complex that my perceived median. A lot of apps really just
>> want data to be fetched out and then passed to jackson (implicitly) and
>> pushed out as a REST response in JSON or some other serialization
>> protocol.
>>
>> So while we could try and keep the stance that such a solution should
>> remain out of scope of Hibernate ORM core, we should have a very smooth
>> integration with something like MapStruct to create such bounded DTO on
>> the fly. Ideally with as close to zero code as possible from the user
>> point of view.
>> I can't really describe how that could look like because I am not
>> familiar enough with MapStruct but I think it should have the following
>> characteristics:
>>
>> 1. do an implicit binding between the mapped object graph and a detached
>> object graph with a 1-1 mapping of type and replacing lazy objects and
>> collections with null. That's the smoothest approach and the most
>> common use case but also the one where an inexperienced person could
>> shoot at someone else's foot
>> 2. do a binding between the mapped object graph and a detached version of
>> that object graph with a 1-1 mapping of type, but declaratively
>> expressing the boundaries for the detached version. This enforces a
>> clear thinking of the boundaries and will load lazy data in case the
>> object graph loaded is missing a bit. I like the idea on principle but
>> I think it overlaps a lot with the fetch graph.
>> 3. offer a full integration between MapStruct and Hibernate ORM by
>> letting people express a full fledge MapStruct transformation between
>> the managed object graph and a different target structure
>>
>> I favored MapStruct over Dozer because we know the MapStruct lead quite well ;)
>>
>> Note however that the MapStruct approach requires an explicit object
>> copy, it feels a bit sad to have to double memory consumption. But that
>> might be a good enough approach and bypassing the managed object
>> creation leads to questions around the Persistence Context contract
>> where loading an object supposedly means it will be in the PC.
>> Maybe a constructor like query syntax allowing to reference a MapStruct
>> conversion logic might work?
>>
>> select mapStruct('order-and-items', o) from Order o left join fetch o.items
>>
>> Emmanuel
>>
>>
>> On Wed 17-04-19 14:29, Vlad Mihalcea wrote:
>>> Hi,
>>>
>>> Although I keep on seeing this request from time to time, I still think
>>> it's more like a Code Smell.
>>> Entities are useful for when you plan to modify them. Otherwise, a DTO
>>> projection is much more efficient, and you don't suffer from
>>> LazyInitializationException.
>>>
>>> With the ResultTransformer, you can even build graphs of entities, as
>>> explained in this article;
>>>
>>> https://vladmihalcea.com/2017/04/03/why-you-should-use-the-hibernate-resulttransformer-to-customize-result-set-mappings/
>>>
>>> Due to how Hibernate Proxies are handled, without Bytecode Enhancement,
>>> it's difficult to replace a Proxy with null after the Session is closed. If
>>> we implemented this, we'd have to take into consideration both Javassist
>>> and ByteBuddy as well as ByteCode Enhancements.
>>>
>>> all in all, the implementation effort might not justify the benefit, and
>>> I'm skeptical of offering a feature that does not encourage data access
>>> Best Practices.
>>>
>>> Vlad
>>>
>>> On Wed, Apr 19, 2017 at 2:18 PM, Christian Beikov <
>>> christian.beikov at gmail.com> wrote:
>>>
>>>> Hey Romain,
>>>>
>>>> I don't think it is a good idea to expose entities directly if you
>>>> really need a subset of the data.
>>>> Reasons for that thinking are that it gets hard to define what needs to
>>>> be fetched or is safe to be used for a particular use case. Obviously
>>>> serialization is like a follow-up problem.
>>>> I see 2 possible solutions to the problem and both boil down to the use
>>>> of DTOs.
>>>>
>>>> 1. Use an object mapper(e.g. Dozer) that maps entity object graphs to
>>>> custom DTO types.
>>>> 2. Use specialized DTOs in queries.
>>>>
>>>>
>>>> Implementing 1. does not help you with lazy loading issues and 2. might
>>>> require very intrusive changes in queries which is why I implemented
>>>> Blaze-Persistence Entity Views
>>>> <https://github.com/beikov/blaze-persistence#entity-view-usage>.
>>>> This is a library that allows you to define DTOs with mappings to the
>>>> entity. In a query you can define that you want results to be
>>>> "materialized" as instances of the DTO type.
>>>> This reduces the pain induced by properly separating the "presentation
>>>> model" from the "persistence model" and at the same time will improve
>>>> the performance by utilizing the mapping information.
>>>> I don't want to advertise too much, just wanted to say that I had the
>>>> same issues over and over which is why I started that project.
>>>>
>>>> Mit freundlichen Grüßen,
>>>> ------------------------------------------------------------------------
>>>> *Christian Beikov*
>>>> Am 19.04.2017 um 10:51 schrieb Romain Manni-Bucau:
>>>>> Hi guys,
>>>>>
>>>>> Short sumarry: Wonder if hibernate could get a feature to kind of either
>>>>> unproxy or freeze the entities once leaving the managed context to avoid
>>>>> uncontrolled lazy loading on one side and serialization issues on another
>>>>> side.
>>>>>
>>>>> Use case example: a common example is a REST service exposing directly
>>>>> hibernate entities (which is more and more common with microservice
>>>>> "movement").
>>>>>
>>>>> Objective: the goal is to not need any step - or reduce them a lot -
>>>>> between the hibernate interaction and a potential serialization to avoid
>>>>> issues with lazy loading and unexpected loading. Today it requires some
>>>>> custom and hibernate specific logic in the serializer which kind of
>>>> breaks
>>>>> the transversality of the two concerns (serialization and object
>>>>> management/loading).
>>>>>
>>>>>
>>>>> Implementation options I see:
>>>>>
>>>>> 1. a callback requesting if the lazy relationship should be fetched,
>>>>> something like
>>>>>
>>>>> public interface GraphVisitor {
>>>>> boolean shouldLoad(Object rootEntity, Property property);
>>>>> }
>>>>>
>>>>> 2. An utility to remove any proxy potentially throwing an exception and
>>>>> replacing the value by null or an empty collection, something like
>>>>>
>>>>> MyEntity e = Hibernate.deepUnproxy(entity);
>>>>>
>>>>> 3. A switch of the proxy implementation, this is close to 2 but wouldn't
>>>>> require a call to any utility, just a configuration in the persistence
>>>> unit.
>>>>> Side note: of course all 3 options can be mixed to create a single
>>>> solution
>>>>> like having 3 implemented based on 1 for instance.
>>>>>
>>>>> Configuration proposal: this would be activated through a property in the
>>>>> persistence unit (this shouldn't be only global IMHO cause otherwise you
>>>>> can't mix 2 kind of units, like one for JSF and one for JAX-RS to be
>>>>> concrete). This should also be activable as a query hint i think - but
>>>> more
>>>>> a nice to have.
>>>>>
>>>>>
>>>>> What this feature wouldn't be responsible for: cycles. If relationships
>>>> are
>>>>> bidirectional then the unproxied entity would still "loop" if you browse
>>>>> the object graph - this responsability would stay in the consumer since
>>>> it
>>>>> doesn't depend on hibernate directly but more on a plain object handling.
>>>>>
>>>>> What do you think?
>>>>>
>>>>>
>>>>> Romain Manni-Bucau
>>>>> @rmannibucau <https://twitter.com/rmannibucau> | Blog
>>>>> <https://blog-rmannibucau.rhcloud.com> | Old Blog
>>>>> <http://rmannibucau.wordpress.com> | Github <https://github.com/
>>>> rmannibucau> |
>>>>> LinkedIn <https://www.linkedin.com/in/rmannibucau> | JavaEE Factory
>>>>> <https://javaeefactory-rmannibucau.rhcloud.com>
>>>>> _______________________________________________
>>>>> hibernate-dev mailing list
>>>>> hibernate-dev at lists.jboss.org
>>>>> https://lists.jboss.org/mailman/listinfo/hibernate-dev
>>>> _______________________________________________
>>>> hibernate-dev mailing list
>>>> hibernate-dev at lists.jboss.org
>>>> https://lists.jboss.org/mailman/listinfo/hibernate-dev
>>>>
>>> _______________________________________________
>>> hibernate-dev mailing list
>>> hibernate-dev at lists.jboss.org
>>> https://lists.jboss.org/mailman/listinfo/hibernate-dev
>> _______________________________________________
>> hibernate-dev mailing list
>> hibernate-dev at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/hibernate-dev
> _______________________________________________
> hibernate-dev mailing list
> hibernate-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/hibernate-dev
More information about the hibernate-dev
mailing list