JPA manually load collections - java

I have an entity holding a collection (#OneToMany) which loads lazily. So far so good. If I load the entire list of entity objects (findAll()) I don't want the collection loaded at all. I don't access the collection therefore I assumed it will not be loaded before returning it from a REST endpoint, but it seems like Jackson accesses it when parsing it into JSON.
Currently I iterate over the entire entity list and set the collection to NULL. This seems like a very poor way of doing it, is there a way to ONLY manually load the collection with a specially prepared #Query and not load it automatically (either LAZY no EAGER) at all? Are #JsonViews the correct way to go or should I remove the #OneToMany annotation (I guess then I lose the mapping for the queries that actually do load the collection)? Any other suggestions?
Examplecode
#Entity
#Entity
public class Entity {
#OneToMany(targetEntity = Child.class)
private List<Child> children;
}
Jersey Resource
#GET
#Produces({MediaType.APPLICATION_JSON})
public List<Entity> getAllEntities() {
List<Entity> entities = entityService.findAll();
entities.forEach(e-> e.setChildren(null));
return entities ;
}
Repository = JpaRepository with default findAll() implementation.
thanks

Since you mentioned 'suggestion', I faced the same problem myself and I decided to implement custom DTOs to be sent in the API response. So I ommitted these collection fields and all other I did not want the json processors to touch.
I did implement my set of DTOs mirroring actual persisted entities, but there might be some other mappers to do the job

A few time ago, I asked a question about designing model classes for a REST API. There might be some information there useful for you.
Instead of reusing the same model classes for persistence and for the REST API, I've realized the best approach was creating different models. In some situations you don't want the persistence model to be the same as the model you use in your API. So, defining different models is the way to go.
And I chose MapStruct to map from one model to other.

Related

How to serialize lazy loaded Hibernate collections (like PersistentSet) outside a DB session

I am developing a Spring MVC facade to access to a number of services. There are no DTOs implemented, and due to the magnitude, it is currently not an option to do so.
Serialization is done by Jackson directly to entities returned to the controllers as a result of transactional invocations to methods in the services, which fetch the entities from DB through the ORM (Hibernate).
The problem comes with entities that have collection attributes (such as Sets) from one-to-many or many-to-many relations, that Hibernate returns as PersistentCollections (like PersistentSet), and are lazy loaded, due to which, can't be read outside the scope of the DB session (which is when Jackson is attempting to serialize the response from the Controller).
Ideally, I would like Hibernate to return Java collections of proxies (HibernateProxy) that do maintain a reference (identifier) to the entity they wrap. Could also work to keep using specialized data structures (like PersistentCollection) but keeping references to the items wrapped, since once wrapped, they can only be retrieved from within a map that lives in the BD session, and without it, the key to the collection is completely useless (why do it like that? what if we don't want the whole item, and just it's identifier to be serialized as a reference? sigh).
I wonder...
Is it possible to force Hibernate to return Java collections of proxies wrapping entities?
If not, is it possible to extend Hibernate collections (like PersistentCollection) to maintain references to the entities wrapped, in order to read them in a specialized Jackson-Hibernate serializer?
If not, is it possible to convert Hibernate collections to Java collections before closing the BD session, without using additional data structures, besides the entity itself (i.e. convert the collection back to a Java type)?
Well, you can just join fetch the collection with e.g. HQL select u from User u join fetch u.groups and annotate the groups property in the User entity with #JsonView(ReferenceJsonView.class) with interface ReferenceJsonView { Integer getId(); }, but that would fetch more state than necessary. I would recommend you look into implementing proper DTOs which can be done quite easily with Blaze-Persistence Entity Views.
Blaze-Persistence is a query builder on top of JPA which supports many of the advanced DBMS features on top of the JPA model. I created Entity Views on top of it to allow easy mapping between JPA models and custom interface defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure the way you like and map attributes(getters) via JPQL expressions to the entity model. Since the attribute name is used as default mapping, you mostly don't need explicit mappings as 80% of the use cases is to have DTOs that are a subset of the entity model.
Assuming you have an entity model like this
#Entity
public class User {
#Id
Integer id;
String username;
#ONeToMany
Set<Group> groups;
}
#Entity
public class Group {
#Id
Integer id;
String name;
}
A DTO mapping for your model could look as simple as the following
#EntityView(User.class)
interface UserDto {
Integer getId();
String getUsername();
Set<GroupDto> getGroups();
}
#EntityView(Group.class)
interface GroupDto {
Integer getId();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
UserDto dto = entityViewManager.find(entityManager, UserDto.class, id);
But the Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
It will only fetch the mappings that you tell it to fetch and all mappings are validated at boot time so nothing can go wrong at runtime.

Entity Model or Pojo Class as a return object of REST API

I am working with REST API,
Is there any wrong if given the list of Model Class Objects as response directly to the user.
or should I need to map those Actual Model class to any POJA class before Returning?
eg :
if the API is forgetting all Users ("/Users")
then is it a good coding method to return directly
return userRepository.findAll();
or need to convert it to any List<UserPOJO> before returning?
Or is there any good codding standards?
From my experience, it is usually better to map the Entities to equivalent POJO classes.
Here are a few reasons:
1) Most of the time you do not need all the data that is stored in an entity. You can map only the subset that is needed in the response.
2) From a security perspective, it is always good to have some sort of a middle ground where you filter out the sensitive data that should not actually put in the response. Or only for certain users which you can decide during the mapping.
3) Hibernate objects are not plain objects, they are proxies. This may cause unnecessary lazy loading for example of #OneToMany and #ManyToMany relations. You should be able to control that and from my experience, Jackson loads all things possible, unless you annotate it with a #JsonIgnore.
Unless you are working with a very simple and not security-heavy app, then I would stay with Hibernate objects. But otherwise, which is most cases, I would go for the mapping.

Make JPA entity field immutable in REST environment

There are two simple JPA entities for Jersey REST web-service. Basically business item has a creator which refers to a user. When serializing it is not necessarily to show the creator of the business item to the client, so JsonIgnore annotation is there. Assume that I allow every user to update BusinessItem name via HTTP PUT request, but not to update creator value.
#Entity
public class BusinessItem {
#GeneratedValue(strategy = AUTO)
#Id
Long id;
String name;
#JsonIgnore
#ManyToOne
#JoinColumn(name = "creator_id", nullable = false, updatable = false)
User creator;
}
#Entity
public class User {
#GeneratedValue(strategy = AUTO)
#Id
Long id;
String name;
#OneToMany(fetch = LAZY, mappedBy = "creator")
List<PhotoSpot> createdPhotoSpots;
}
The problem is that once PUT request with JSON body is received from a client and deserialized then creator field would be null. Then in order to update entity in a database I would need to retrieve a creator value from the DB by the business item id, substitute in the deserialized entity and only then apply update to the database. This all sounds like not elegant and boiler plate.
What would be an elegant solution for this type of problem?
The direct association between a service and an entity can be a pragmatic design in very simple applications. However in many case this is not a suitable option. Managing properly entity relationships can be a good reason to have a more structured design.
In the usual design of standard MVC applications, it is a good practice not to use the entity directly as a JavaBean accessed via the View / page (the entity is an Enterprise JavaBean in an EJB container, not to be confused) . The implementation of a TransferObject pattern is an usual solution (beware, the sequence documented in that link is for a data retrieval operation, not an update). The controller commonly assumes the construction of the TransferObject. It then becomes a recommended candidate for a DAO operation.
A REST service is not very different from an MVC pattern: in fact this is an Entity-Control-Boundary pattern (in the case of Jersey <= 2 applications, the distinction can be quite subtle, even if this should evolve in Java EE 8). The service itself is a Boundary replacing the View.
In other words, according to Core J2EE Patterns, the elegant solution would be to feed a TransferObject with your PUT parameters: this object is then transmitted to the DAO. Then the DAO layer just has to retrieve a properly managed entity from the database to get the entities relationships and report the transferred values to update into the managed entity while preserving the relationships (this can be done with a DAO).
Java EE design can be quite challenging. The platform provides out of the box components very similar to pattern shapes. But in several cases these are not replacements. For example an EntityManager looks like a DAO. But using an explicit DAO usually provides a clear and understandable code while using directly the EntityManager can be quite verbose as transactions are not encapsulated.
Conclusion
In your situation, what seems important to me is the use of a DAO to encapsulate your database operations (this is only if you really need to map the relationships, otherwise a #Transient annotation would be a solution). You will anyway have to retrieve a managed entity before performing the merge(...) operation. The use of the TransferObject is not mandatory, this is just an advice to have a proper design. In many case this can lead to verbose code. You have several solutions to limit this: a simple Map can limit the code, a utility such as BeanUtils can also be precious.
But avoiding a basic transfer operation in setting up a DAO can be challenging. In your case this would induce the use of a MultivaluedMap in the DAO layer, which does not seem a very good idea on a dependency point of view as it links the Model/Entity and the View/Boundary components. This is probably why Core J2EE patterns introduces the TransferObject.

Object Relational mapping and performance

I am currently working on a product that works with Hibernate (HQL) and another one that works with JPQL. As much as I like the concept of the mapping from a relational structure (database) to an object (Java class), I am not convinced of the performance.
EXAMPLE:
Java:
public class Person{
private String name;
private int age;
private char sex;
private List<Person> children;
//...
}
I want to get attribute age of a certain Person. A person with 10 children (he has been very busy). With Hibernate or JPQL you would retrieve the person as an object.
HQL:
SELECT p
FROM my.package.Person as p
WHERE p.name = 'Hazaart'
Not only will I be retrieving the other attributes of the person that I don't need, it will also retrieve all the children of that person and their attributes. And they might have children as well and so on... This would mean more tables would be accessed on database level than needed.
Conclusion:
I understand the advantages of Object Relational Mapping. However it would seem that in a lot of cases you will not need every attribute of a certain object. Especially in a complex system. It would seem like the advantages do not nearly justify the performance loss. I've always learned performance should be the main concern.
Can anyone please share their opinion? Maybe I am looking at it the wrong way, maybe I am using it the wrong way...
I'm not familiar with JPQL, but if you set up Hiernate correctly, it will not automatically fetch the children. Instead it will return a proxy list, which will fetch the missing data transparently if it is accessed.
This will also work with simple references to other persistent objects. Hibernate will create a proxy object, containing only the ID, and load the actual data only if it is accessed. ("lazy loading")
This of couse has some limitations (like persistent class hierarchies), but overall works pretty good.
BTW, you should use List<Person> to reference the children. I'm not sure that Hibernate can use a proxy List if you specify a specific implementation.
Update:
In the example above, Hibernate will load the attributes name, age and sex, and will create a List<Person> proxy object that initially contains no data.
Once the application accesses calls any method of the List that requires knowledge of the data, like childen.size() or iterates over the list, the proxy will call Hibernate to read the children objects and populate the List. The cildren objects, being instances of Person, will also contain a proxy List<Person> of their children.
There are some optimizations hibernate might perform in the background, like loading the children for other Person objects at the same time that might be in this session, since it is querying the database anyways. But whether this is done, and to what extend, is configurable per attribute.
You can also tell hibernate to never use lazy-loading for certain references or classes, if you are sure you'll need them later, or if you continue to use the persistent oject once the session is closed.
Be aware that lazy loading will of course fail if the session is no longer active. If for example you load a Person oject, don't access the children List, and close the session, a call to children.size() for example will fail.
IIRC the hibernate session class has method to populate all not-yet-loaded references in a persistent oject, if needed.
Best read the hibernate documentation on how to configure all this.

How can I do paging with #OneToMany collections

Suppose I have a Post entity and a Comment entity and a one to many relationship:
#Entity class Post {
...
#OneToMany
List<Comment> comments;
...
}
How can I achieve paging like this:
Post post = //Find the post.
return post.getComments().fetch(100, 10); // Find the 11th page (page size 10);
Is it possible to emulate dynamic paging with #OneToMany collections on top of JPA,
or do we have to rewrite the association mechanism of JPA totally ? (e.g. create a PersistentList collection type that could manage the paging, sorting and searching).
P.S.: I recently found the Play! framework uses a very interesting lib on top of JPA: Siena. Siena is very easy to use, and is a good abstraction on top of JPA/Hibernate. But I can't find how to do paging with its associations.
Update:
Play framework has a query syntax similar to Django:
Post.findAll().from(100).fetch(10); // paging
where
Post.findAll()
will return a JPAQuery object, a customized query type in Play.
But with associated collections, e.g.:
Post.comments
will just return a List, which doesn't support paging or other queries.
I was wondering how to extend it, so that
Post.comments
will also return a JPAQuery object or similar, then you can query on the "query" collection:
Post.comments.from(100).fetch(10);
or insert a new Comment without actually fetching any of the comments:
Post.comments.add(new Comment(...));
On my first thought, we could create a subclass of List, then the Post class would become:
#Entity class Post {
...
#OneToMany
QueryList<Comment> comments;
...
}
and QueryList will have fetch(), from() methods that indirect to JPAQuery's.
But I don't know whether Hibernate/JPA will recognize this, or interfere with it.
Is it possible to emulate dynamic paging with #OneToMany collections on top of JPA (...)
Not supported. The standard approach would be to use a JPQL query to retrieve the comments for a given post and and to use Query#setFirstResult(int) and Query#setMaxResults(int).
On my first thought, we could create a subclass of List, (...). But I don't know whether Hibernate/JPA will recognize this, or interfere with it.
It obviously won't without an heavy patch to drastically change the default behavior.
I think the "right" way might be more like:
#Entity
class Post {
...
public GenericModel.JPAQuery getComments() {
return Comment.find("post_id = ?", post_id);
}
}
and then use one of the fetch methods in JPAQuery:
// fetch first page of results, 25 results per page
post.getComments().fetch(1,25);

Categories