• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

JPA/Hibernate and Failed to Lazily Initialize a Collection

 
Ranch Hand
Posts: 45
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello,

After some reading and looking at examples this is still blowing my pea brain and I don't know what specifically to do to fix this. I am trying to update my configuration for Authentication and UserDetails by including an authorities list in my User. The user is being created and the role is stored successfully (attached), but the problem comes of course when trying to get the authorities information out of the User. I first saw the error when trying to login, but essentially just calling 'user.getAuthorities()' will trigger it.

Seemingly, EAGER loading is not good practice and not the way to go.
If EAGER loading is okay in this case, there's a Bag error that comes up, or something like that, because I used EAGER on another Entity earlier... so I haven't looked into this yet.
This article (https://www.baeldung.com/java-jpa-lazy-collections) seems to address this issue (I think the answer lies with point 3), but still don't know where'd I put it.
Aside from that, I'm not sure what to try, but this setup is pretty basic so I feel like there's an easy solution I'm missing.

Any help appreciated, thank you.







authorities.png
[Thumbnail for authorities.png]
users.png
[Thumbnail for users.png]
 
Saloon Keeper
Posts: 27881
197
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The reason you generally want to avoid eager fetching is that if you're not careful about your Entity relationships, you could accidentally suck the entire database into RAM.

In the case where you want to pull in a parent and child one-to-many (which is basically what user/role amount to), you'd fetch the parent, and then, while still attached, reference the child. One way to do that would be to simply access the first element in the child. That will cause all of the children to get fetched at which point you can safely detach if you want.

Actually, I think you can get the same effect using the size() method on the child collection, but I don't have proof in front of me right now.
 
Wayne Woodrow
Ranch Hand
Posts: 45
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for the response, much appreciated. I did see something like this, but where would I put that method call?

I tried calling it inside the UserDetailsServiceImpl, but no luck. Aside from that I feel like it should be part of the call inside the UserRepository perhaps, except there's no implementation in there it is simply extending JpaRepository.



 
Marshal
Posts: 8880
638
Mac OS X VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
@OP

Please mention version of Hibernate you use, that may be important in finding a solution, because Hibernate's behaviour in general may be different depending on version you use.

Then, please research those and see if they are applicable in your scenario:
- Hibernate.initialize(user.getAuthorities()) before you pass to UserDetailsImpl
- @Transactional annotation on a method to keep session active (there might be consequences, need to understand how exactly that works before you use)
 
Tim Holloway
Saloon Keeper
Posts: 27881
197
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I've got to admit that there's more there than I can easily digest.

In a vanilla JEE container security system, it would be simple for me, but Spring Security is a little more complicated and I've never used it for role-based access control (so far!)

I read up a bit, and this looks like a good source: https://www.baeldung.com/role-and-privilege-for-spring-security-registration

Basically, as I understand it, Spring Security takes a list of security roles (say, from a database) and builds Authorities (which is a Spring Security construct) from there.

So a likely solution would be a UserDao that looked something like this:


I'll leave the implementation of these methods as an exercise You needn't define the Interface, since you only would (presumably!) have one implementation, I just did it that way to keep things short. If using Spring Data Repository annotations, you should be able to define all these methods using the basic magic that that facility supplies.

The key takeaway, if I'm not mistaken is that the Spring Data Authority builder wants a list of Strings defining the Roles, which you can obtain by invoking one of the above methods and pulling the role name property from each Role in the returned collection.

Since I'm operating at a considerable distance from practical implementation, there are likely to be things that aren't quite like I've outlined, but I think I've got the general direction.
 
Bartender
Posts: 2436
13
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Wayne,
I found an example on Github for educational purpose. To avoid the lazy intializaion error, this author annotation the method by @Transactional.
https://github.com/springframeworkguru/ssc-brewery/blob/db-user-details-svc/src/main/java/guru/sfg/brewery/services/BeerOrderServiceImpl.java
 
Liutauras Vilda
Marshal
Posts: 8880
638
Mac OS X VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Himai Minh wrote:Wayne,
I found an example on Github for educational purpose. To avoid the lazy intializaion error, this author annotation the method by @Transactional.


I said that already, but as mentioned, need to understand the full @OPs context, because transactional annonation is not meant just to solve problem to have session active.

Can give tomorrow or other day an example, how that could cause an unwanted outcome.
 
Tim Holloway
Saloon Keeper
Posts: 27881
197
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
@Transactional is primarily to ensure that a database operation functions as an atomic unit, instead of possibly losing sync between tables when you do multiple operations in series.

What is more important here is whether the Entities in question are attached or detached.

An attached Entity object has an invisible connection to an EntityManager. Application code cannot see it, but the code weaver that makes JPA possible naintains and uses it.

A detached Entity lacks that connection and it's basically just the what-you-see-is-what-you get POJO.

You do not need to worry much about eager/lazy fetch for an attached object. If you want the associated roles for a user, just use the "getRoles()" method to obtain the User's Role collection and start accessing elements in that collection. If the Roles haven't already been fetched (and possibly cached, they will nonetheless be fetched when you access them.

A detached User, on the other hand, has to worry about eager/lazy fetch. Since it has no connection to the database, attempting to fetch the roles property will  return the roles collection IF you did an eager fetch OR manually accessed it before detaching. However if you did NOT do one of the preceeding, you'll get back a proxy collection object that stands in for the roles and accessing it will throw an Exception.

On the whole, I recommend spending as much time detached as possible. If you are attached, it's very easy to push unintended changes to the database and you may be holding locks that degrade performance. On the other hand, if you make changes to detached objects, you have to re-attach them before they can be persisted. And one thing that's very important to note is that re-attaching an object does not simply modify the original detached object, it creates a whole new attached copy. That is, the object returned from a JPA merge() satisfies the "equals()" method, but not the "==" operation. Once merged, you should discard the pre-merge (detached) objects and work with the merged (attached) ones.

In most of my JPA apps, I have 3 persistence layers. The lowest defines the Entity objects. The next level up are the DAO's for those objects, where each DAO does find/CRUD opeations for one and only one table (or if tightly-bound, parent/child table set).

The next level up is the persistent object service level. This level works with sets of related objects. What I refer to as "working sets". They can retrieve a network of objects required for a business function as a detached set of objects. They can also accept a detached network of objects (working set), re-attach them, and invoke the necessary DAOs. Application code never invokes DAOs directly nor works with attached Entities. Service methods are all @Transactional, and it makes for a very tidy organization.
 
Wayne Woodrow
Ranch Hand
Posts: 45
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I was waiting to respond until I had better results to show, but just wanted to say thanks for your time responding and for the helpful information. It's still sinking in and I'm looking to test a couple of configurations to get a better understanding.

To an earlier question, it's on spring-security-core 5.5.3 right now.

At the moment, by adding the EAGER fetch to this ElementCollection, it seems to be working as expected and I 'm able to retrieve the roles for the logged in user. However, having not worked on this for a while and then coming back to it, I actually deleted a UserDTO and UserMapper class that I had initially created by following some examples, but didn't really understand the value of having them there. The article provided by Tim looks like it will be very helpful though, so I'm going to try recreating these Service or DAO classes a bit more carefully this time. I'll give some success/failure updates once I have some results

 
Himai Minh
Bartender
Posts: 2436
13
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Can you try to use @ManyToMany to set up the relationship between User and the Set<GrantedAuthority> instead of making the authorities as an ElementCollection?
 
Wayne Woodrow
Ranch Hand
Posts: 45
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Himai Minh wrote:Can you try to use @ManyToMany to set up the relationship between User and the Set<GrantedAuthority> instead of making the authorities as an ElementCollection?



This is somewhat of a deviation from my earlier question, but here is a repo with a working build right now: https://github.com/Wawa87/demo

There is a separate class for the Authority instead of having it as an ElementCollection.

I think next I will try bringing the GrantedAuthorities back into the User class as a list again.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic