Hibernate Bytecode Instrumentation: Set fetched property values to their fields right away - java

I'm working on an enterprise application that uses Hibernate and EJB, and I'm utilizing Hibernate's Bytecode instrumentation to implement true lazy-loading of properties having bidirectional #OneToOne associations. I have a service method implemented using EJB, and as we all know, EJB uses RMI, which uses native Java serialization and deserialization to facilitate RPC invocations. The service method returns an entity with needed properties already fetched using JPQL, but since Hibernate doesn't set the fetched properties eagerly to their target fields, clients calling the service method end up receiving entities with properties having null values. Aside from calling the property getters manually before returning the entity, is there a way to tell Hibernate to set fetched property values automatically to their corresponding fields?
I'm using Hibernate 5.3.15 and JBoss EAP 7.2.8.

First of all, EJB doesn't necessarily use RMI, I guess what you mean is EJB remoting. There is no way that I know of to force field initialization except for initializing the fields through some means (access). One way to overcome this is to use DTOs that simply do not do any lazy initialization.
I think that this might be a bug in the serialization code of Hibernate for such bytecode enhanced proxies, so please create an issue in the issue tracker(https://hibernate.atlassian.net) with a test case(https://github.com/hibernate/hibernate-test-case-templates/blob/master/orm/hibernate-orm-5/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java) that reproduces the issue.
If you want to take the DTO approach, I think this is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(User.class)
public interface UserDto {
#IdMapping
Long getId();
String getName();
UserDetailsDto getDetails();
#EntityView(UserDetails.class)
interface UserDetailsDto {
#IdMapping
Long getId();
String getFirstname();
}
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
UserDto a = entityViewManager.find(entityManager, UserDto.class, id);
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
Page<UserDto> findAll(Pageable pageable);
The best part is, it will only fetch the state that is actually necessary!

Related

Use proxies with Hibernate runtime bytecode enhancement

I'm using Spring Boot 2.7.5 with Hibernate 5.6.12.Final and apply bytecode enhancement at build-time via hibernate-enhance-maven-plugin. It works great and prevents eagerly fetching #OneToOne relationships, as described here https://vladmihalcea.com/hibernate-lazytoone-annotation/.
However, I found that all lazy relationships do not use proxies anymore but are fetched from the database when I use the getter (which has been instrumented by the maven plugin at build time). Basically, what I would like to do is to still use proxies with bytecode enhancement. Something similar is available at runtime https://in.relation.to/2019/07/30/bytecode-proxy/, but I can't find a way to do it at build-time.
For a bit of context, I need proxies for lazy-loaded properties because it allows me to apply custom logic in entity->dto mapper (using Mapstruct) based on whether the proxy has been initialized or not. In some cases, I must trigger an initialization manually if a Hibernate session is available (and prevent LazyInitializationException).
Any suggestion is greatly appreciated!
If you want to avoid LazyInitializationException for your DTO mapping, you should rather try to avoid doing the mapping in Java code and instead use a solution that can take the mapping down to the HQL/SQL level.
I think this is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for a possible use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(User.class)
public interface UserDto {
#IdMapping
Long getId();
String getName();
Set<RoleDto> getRoles();
#EntityView(Role.class)
interface RoleDto {
#IdMapping
Long getId();
String getName();
}
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
UserDto a = entityViewManager.find(entityManager, UserDto.class, id);
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
Page<UserDto> findAll(Pageable pageable);
The best part is, it will only fetch the state that is actually necessary!

Spring projection with entity inside

I need in metainfo for entity (hierarchy level from recursive sql query) so i created next projection
#Value
public class ProjectionObject{
MyEntity entity;
int metainfo;
}
#Query(value = "select my_entity.*, 1 as metainfo from my_entities", nativeQuery = true)
List<ProjectionObject> findSome();
But it returns List<List> but i expect List.
As result i what to manipulate with ProjectionObject#entity as with managed (by Entity Manager) ProjectionObject#entity, in other word i want to get managed entity with metainfo once without getting f.e. hierarchy Ids and after get entities
I'm not sure Spring Data Projections supports that.
However, this is a perfect use case for 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.
A projection with Entity Views could look as simple as the following
#EntityView(MyEntity.class)
interface ProjectionObject {
#Mapping("this")
MyEntity getEntity();
#Mapping("1")
int getMetaInfo();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
ProjectionObject dto = entityViewManager.find(entityManager, ProjectionObject.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
List<ProjectionObject> findAll();
You can also make use of updatable entity views which allows you to eliminate the entity type completely, which reduces the amount of data fetched and flush back only the parts that you actually want to change:
#UpdatableEntityView
#EntityView(MyEntity.class)
interface ProjectionObject {
#IdMapping
Integer getId();
String getName();
void setName(String name);
#Mapping("1")
int getMetaInfo();
}
Now you can fetch that object and then after changing the state flush it back to the database:
ProjectionObject o = repository.findOne(123);
o.setName(o.getName().toUpperCase());
repository.save(o);
And it will only flush back the name as you will see in the SQL.

How to specify spring data jpa request to load collection of entity properties?

I use spring data JPA. I need in my repository request to load only collection of concrete properties colors:
#Query(value = "SELECT cd.color FROM CalendarDetails cd where cd.userCalendar.userId = :userId")
List<String> findCalendarColorsByUserWithDuplicates(#Param("userId") Long userId);
Provided solution works correctly.
I want simplify it using spring approach to load collection of the repository objects I'd use (repository public interface CalendarDetailsRepository extends JpaRepository<CalendarDetails, Long>):
List<CalendarDetails> findByUserCalendarUserId(#Param("userId") Long userId);
But I need collection of colors! Trying
List<String> findColorByUserCalendarUserId(Long userId);
I get collection of CalendarDetails
Is it possible to improve my last request following spring data approaches to load list of colors?
You can try special Projection mechanisms that Spring Data provides. It will allow you not only to optimize your queries but also to make it with pure java without using #Query.
There are a lot of ways to
make it, but I would recommend the following.
You add an interface that contains getters for the properties that you need to take from entity:
public interface ColorOnly {
String getColor();
}
Then you return the list of this interface' objects:
List<ColorOnly> findColorByUserCalendarUserId(Long userId);
To use the colours from the interface, you just invoke getColor method. You may consider simplifying it with Java 8 streams and map conversions. BTW, this one will only query colour. No other fields will be included into the query Hibernate produces.
Try to add All
findAllByUserCalendarUserId(Long userId);
BTW, IntelliJ IDEA provide very deep support of JPA repositories, so it's prevent a lot of possible issues when you create queries like this one

Initialize JPA-like entities with JDBC

I'm implementing several DAO classes for a web project and for some reasons I have to use JDBC.
Now I'd like to return an entity like this:
public class Customer{
// instead of int userId
private User user;
// instead of int activityId
private Activity act;
// ...
}
Using JPA user and activity would be loaded easily (and automatically specifying relations between entities).
But how, using JDBC? Is there a common way to achieve this? Should I load everiting in my CustomerDAO? IS it possible to implement lazy initialization for referenced entities?
My first idea was to implement in my UserDAO:
public void initUser(Customer customer);
and in my ActivityDAO:
public void initActivity(Customer customer);
to initialize variables in customer.
Active Record route
You could do this with AspectJ ITDs and essentially make your entities into Active Record like objects.
Basically you make an Aspect that advises class that implement an interface called "HasUser" and "HasActivity". Your interfaces HasUser and HasActivity will just define getters.
You will then make Aspects that will weave in the actual implementation of getUser() and getActivity().
Your aspects will do the actual JDBC work. Although the learning curve on AspectJ is initially steep it will make your code far more elegant.
You can take a look at one of my answers on AspectJ ITD stackoverflow post.
You should also check out springs #Configurable which will autowire in your dependencies (such as your datasource or jdbc template) into non managed spring bean.
Of course the best example of to see this in action is Spring Roo. Just look at the AspectJ files it generates to get an idea (granted that roo uses JPA) of how you would use #Configurable (make sure to use the activerecord annotation).
DAO Route
If you really want to go the DAO route than you need to this:
public class Customer{
// instead of int userId
private Integer userId;
// instead of int activityId
private Integer activityId;
}
Because in the DAO pattern your entity objects are not supposed to have behavior. Your Services and/or DAO's will have to make transfer objects or which you could attach the lazy loading.
I'm not sure if there is any automated approach about this. Without ORM I usually define getters as singletons where my reference types are initialized to null by default, i.e. my fetching function would load primitives + Strings and will leave them as null. Once I need getUser(), my getter would see if this is null and if so, it would issue another select statement based on the ID of the customer.

Is is possible to create a custom jpa annotation in java

Jpa one of the big successfull module of jpa and so are its annotation features .I have weird requirement in which i need to create jpa annotation ,one that jpa can process
ex. We have in jpa a table annotation that create a table for this java pojo class.
i need to make another annotation that behaves exactly as what table annotation does + some of my custom reqirements;
what is mean
if i create a customAnnotation like #Anil that is suppose to work same as #Table Annotation does
than
#Anil
public class Anp
{
}
than this should create a table in the database is that possible or not .if it is give me some way to do this
thanks
JPA does not process just any annotation. The JPA implementation processes the annotations that it supports and these are typically just the javax.persistence annotations, and optionally its own extensions. Your JPA provider may allow you to define your own, but this is not going to be very common - look at the docs for your JPA provider if they allow a user to define annotations.
For example, the JPA provider I have used (DataNucleus JPA) allows the user to provide annotations for the class or for the field/property.

Categories

Resources