[hibernate-dev] [feature request][discuss] smoother serializers integration?
Emmanuel Bernard
emmanuel at hibernate.org
Thu May 4 04:20:36 EDT 2017
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
More information about the hibernate-dev
mailing list