Hibernate Lazy Load Error after merge - java

I'm using vanilla Spring MVC with a custom FlashScope implementation. We basically use it to follow the Post-Redirect-Get pattern.
I've run into an odd situation. In my Post I do some searching for the parameters the user entered, and I set those instances onto FlashScope. I see those pieces working just fine.
In the object I place onto FlashScope I have a lazy loaded collection, however when I attempt to access the collection like so:
entity.getLazyLoadedCollection();
I receive the following stacktrace:
ERROR org.hibernate.LazyInitializationException IP127.0.0.1 CV#4c44559c-c576-4732 P#75004 - could not initialize proxy - no Session
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
at core.model.entities.WorkflowState_$$_javassist_36.getFunctions(WorkflowState_$$_javassist_36.java)
The odd thing is that right before the call above I merge it onto the session in my service layer:
getSession().merge(entity);
Hibernate Documentation states that I should call update if I know that I'm working with a new session, but the JavaDocs make it seem like I should call merge...
As a workaround I've done the following:
if (getSession().contains(entity)) {
getHibernateTemplate().merge(person);
} else {
getSession.update(entity);
}
What should I be doing here?

Read the javadoc that you linked carefully: "Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session."
No matter what you pass to merge(), that object doesn't get associated to the session. You need to be working with the object returned from merge().

Never worked with FlashScope, but your error apeears to be because you are trying to access a LAZY collection which has not been initialized, and you are no longer in a layer of your app which has access to the Hibernate Session. If that assumption is correct, you need to initialize the collection where you have access to the Session (e.g., your DAO). Here are 2 basic ways:
Hibernate.initialize(object.getMyLazyCollection());
or
if(object.getMyLazyCollection() != null) {
object.getMyLazyCollection().size(); // forces a collection load
}

Related

Upgraded spring-boot/spring-framework to 2.x.x/5.x.x for Spring Batch Java project and now data not being written/saved to Database (Postgresql)

I recently upgraded/migrated my Spring Batch Java application from spring-boot-starter-parent-1.5.9.RELEASE to -> spring-boot-starter-parent-2.2.4.RELEASE, which subsequently pulls in the 5.X.X (5.2.3.RELEASE to be exact) springframework dependencies (before I was using 4.X.X). Some of the main ones I'm using are:
spring-boot-starter-parent-2.2.4
spring-boot-starter-batch
spring-boot-starter-jpa
spring-boot-starter-web
hibernate-core
hibernate-envers
hibernate-entitymanager
postgresql
For context, my application reads in .csv files and parses out the data and simply writes it to a postgresql database.
After many hours of debugging today, I know see that my first call to write data to the database, which is done by a JpaRepository method called saveAll(), which basically takes an ArrayList (Iterable) of Entities and batch inserts them to database, is failing somewhere when it enters the JdkDynamicAopProxyClass from the Spring AOP library. Previously, I was using the save() method, but this didn't work anymore once I upgraded my dependencies.
I know its failing here because I debugged meticulously and see that once it hits the saveAll() method in my java class that implements the ItemWriter<S> for Spring Batch, it enters the public Object invoke(Object proxy, Method method, Object[] args) method in the JdkDynamicAopProxyClass, and ends up throwing an exception, after doing a huge weird loop in the library code that's hard to follow.
I also debugged my old Application that WAS WORKING when it was running on spring-boot-starter-1.5.9 as I stated previously, and I see that when it gets to that public Object invoke() method (I mentioned above), it returns an ArrayList of the entities (which is correct) to write to the Database when it hits this line of code inside that method:
public Object invoke(Object proxy, Method method, Object[] args) {
// code here...
// this is where I notice a difference in return type from the "working" code vs. "broken
// code"
retVal = invocation.proceed();
// more code here...
Object var12 = retVal;
return var12;
HOWEVER, when I debugged my new migrated code (that was upgraded to spring 2.X.X/5.X.X, I see it returns a DefaultTransactionStatus#14037 object, which clearly is wrong. It then enters the protected TransactionAspectSupport.TransactionInfo createTransactionIfNecessary() method in the TransactionAspectSupport class from the spring-tx library. It will then have the retVal variable in the invoke method I mentioned above equal to null and it will start looping a few times more, over the same parts of code in a circle. It will have the txInfo set as PROPAGATION_REQUIRES_NEW,ISOLATION_SERIALIZABLE. I can click the "Step Into" button in IntelliJ and it will let me step through forever. Its like a infinite loop.
I'm not sure what to post, or if there are any clues here. I googled and found other people have similiar issues, and it seemed to revolve around (possibly) the transaction manager or entity manager and how the Beans were setup in the configuration class.
I tried everything I read, but nothing worked. I'm not an expert with Spring Batch or Spring so maybe I am missing something here.
I also noticed when I was debugging my working code, it had a variable Target = SimpleJpaRepository#11243 and it had some properties like a ArrayList of Providers
Em = Shared EntityManager proxy for target factory [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#6f2b608e]
Provider = HIBERNATE
org.hibernate.Session [0]
org.hibernate.jpa.HibernateEntityManager [1]
org.hibernate.ejb.HibernateEntityManager [2]
The odd thing was when I debugged my "broken" code, it seemed to only have the org.hibernate.jpa.HibernateEntityManager in its List in this variable
If anyone can please let me know if there are some clues pointing to something, I would immensely appreciate it. I really think its a Bean config, Entity Manager/Transaction-issue, but I'm not an expert so I'm not sure. I thought it was a dependency issue at first, but after being on google that changed my mind.

Java container managed transactions

I have encountered a problem and I can't figure out the cause. For the rest of the post, we shall assume that every transaction is container managed and that we use jboss AS 7.X. We have three stateless ejb's. We will call them RestEJB, IntEJB and ProviderEJB. The provider base methods are:
save(){
return getEm().merge(ob);
The core line of the load method is:
load(){
Query query = getEm().createQuery(criteriaQuery);
The base order is something along the lines of RestEJB -> IntEJB -> ProviderEJB.
Now, depending on the order of the operations, we may receive a ARJUNA012117 error in jboss.
The problematic code is this:
RestEJB.someMethod(){
item = IntEJB.save(item)
}
IntEJB.save(Item item){
...
ProviderEJB.save(item)
return ProviderEJB.load(item)
}
However if we rewrite it like this:
RestEJB.someMethod(){
item = IntEJB.save(item)
item = IntEJB.load(item)
}
IntEJB.save(){
...
return ProviderEJB.save(item)
}
IntEJB.load(){
...
return ProviderEJB.load(item)
}
Then everything will work properly. In the above examples, item represents the same Object. Thus, the save and load are done on the same object (which may in turn trigger other fetches). There is no code written between save and load in either of the examples.
The question is this: How come it works when we move the load one ejb up as opposed to loading at the same level ejb as the save?
Since we use hibernate, all the code will be commited to the database only after we exit RestEJB.

Unable to use multiple ebean databases in Play 2

We are setting up a slightly complicated project using Play Framework 2.0.3.
We need to access several databases (pre-existing) and would like to do it using the frameworks built-in facilities (ie. EBean).
We tried to create all model classes within the "models" package, and then map each class with its FQN to the corresponding EBean property in the application.conf:
ebean.firstDB="models.ClassA,models.ClassB,models.ClassC"
ebean.secondDB="models.ClassD"
ebean.thirdDB="models.ClassE,models.ClassF"
This doesn't seem to work:
PersistenceException: Error with [models.SomeClass] It has not been enhanced but it's superClass [class play.db.ebean.Model] is? (You are not allowed to mix enhancement in a single inheritance hierarchy) marker[play.db.ebean.Model] className[models.SomeClass]
We checked and re-checked and the configuration is OK!
We then tried to use a different Java package for each database model classes and map them accordingly in the application.conf:
ebean.firstDB = "packageA.*"
ebean.secondDB = "packageB.*"
ebean.thirdDB = "packageC.*"
This works fine when reading information from the database, but when you try to save/update objects we get:
PersistenceException: The default EbeanServer has not been defined? This is normally set via the ebean.datasource.default property. Otherwise it should be registered programatically via registerServer()
Any ideas?
Thanks!
Ricardo
You have to specify in your query which database you want to access.
For example, if you want to retrieve all users from your secondDB :
// Get access to your secondDB
EbeanServer secondDB = Ebean.getServer("secondDB");
// Get all users in secondDB
List<User> userList = secondDB.find(User.class).findList();
When using save(), delete(), update() or refresh(), you have to specify the Ebean server, for instance for the save() method:
classA.save("firstDB");
I have encounter the same problem and waste a whole day to investigate into it,finally I have got it.
1.define named eabean server
db.default.driver=com.mysql.jdbc.Driver
db.default.url="jdbc:mysql://localhost:3306/db1"
db.default.user=root
db.default.password=123456
db.aux.driver=com.mysql.jdbc.Driver
db.aux.url="jdbc:mysql://localhost:3306/db2"
db.aux.user=root
db.aux.password=123456
now you have two ebean server [default] and [aux] at run time.
2.app conf file
ebean.default="models.*"
ebean.aux= "secondary.*"
Now entiies under package models.* configured to [default] server and entities under package secondary.* configured to [aux] server. I think this may related to java class enhancement or something. You don't need to separate Entities into different packages, but if entities of different ebean servers are under same package, it may cause weird trouble and exceptions.
When using you model, save/delete/update related method should add server name as parameter
Student s = new Student(); s.save("aux");
When use finder,you should define your finder as
public static Finder find = new Finder("aux",Long.class,Student.class);
Might not be the same case, I ran to this SomeClass not enhanced PersistenceException with Play 2.1.0,
and only what was missing was a public declaration in SomeClass model class that I had forgotten..
In Play 2.1.0 the error message was a little different:
PersistenceException: java.lang.IllegalStateException: Class [class play.db.ebean.Model] is enhanced and [class models.Address] is not - (you can not mix!!)
This solved my issue with saving to my db table and resolving the error:
"javax.persistence.PersistenceException: The default EbeanServer has not been defined ? This is normally set via the ebean.datasource.default property. Otherwise it should be registered programatically via registerServer()"

GWT Autobean frozen when saving graph

I am using GWT 2.4 with the editor and request factory frameworks. I have a model, Trip, which has an Address 'origin' and an Address 'destination'. When creating a Trip via the UI, the two addresses are created automatically and assigned to the Trip. User fills out details and saves. For some reason, I am getting the 'autobean frozen error' when trying to persist to the server. This code worked in GWT 2.3 and I cant switch back. I am hoping its not a bug in GWT 2.4. Here is some sample code of what I am doing:
RequestContext request = requestFactory.request();
TripProxy trip = request.create(TripProxy.class);
trip.setOrigin(request.create(AddressProxy.class));
trip.setDestination(request.create(AddressProxy.class));
driver.edit(trip, request);
this.trip = trip;
// … on save button clicked (different method)
RequestContext request = driver.flush();
request.save(trip).with(driver.getPaths()).fire(someReceiverImpl);
Results in:
java.lang.IllegalStateException: The AutoBean has been frozen
at com.google.web.bindery.autobean.shared.impl.AbstractAutoBean.checkFrozen(AbstractAutoBean.java:195)
at com.google.web.bindery.autobean.shared.impl.AbstractAutoBean.setProperty(AbstractAutoBean.java:270)
at sun.reflect.GeneratedMethodAccessor53.invoke(Unknown Source)
The call to fire completes successfully but somewhere from within requestfactory, the above error is thrown. Curiously, the entity is saved on the server however, validations are not enforced. When I simplify the model and remove the Address associations, the validation and save works. My main issue is the autobean frozen error; the validation stuff is secondary.
EDIT: On further investigation I found that the entities are making it to the server okay and persisting as expected. Its upon return that the above exception is thrown. AddressProxy is a ValueProxy and it looks like RF doesnt like Trip coming back with these associations. Returning null 'fixes' the problem but this obviously wont work long term.
I know this is a lot more than you're asking for, but these 3 tips have helped me out (from here):
Trying to edit locked entity.
If an entity is frozen ( locked for changes) you cannot:
change its properties
use it in requestContext method calls.
If you try to do it, you will receive the exception : java.lang.IllegalStateException: The AutoBean has been frozen.
When entity may be frozen?
every entity returned as a response is frozen
every entity which has been used in requestContext call will be frozen.
In first situation solution is easy – you just have to unlock given entity. In order to do that you must use instance of your RequestContext class and call edit() method.
StudentRequest req1 = requestFactory.studentRequest();
StudentProxy s2 = req1.edit(s1);
In second situation you should not use given entity any more, It cannot be edited because it has already a requestContext assigned. If you want to change it you must retrieve instance of this entity from server again and follow instructions for point a).
Trying to call requestContext.edit() on entity which already has a requestContext assigned.
If you have retrieved the entity from the server or created a new one, and afterwords you are trying to use ANOTHER RequestContext to edit it e.g. in this way:
StudentRequest req = requestFactory.studentRequest();
s1 = req.create(StudentProxy.class);
// s1 is connected with "req" and one context is just enough for it
StudentRequest reqZZZ = requestFactory.studentRequest();
reqZZZ.edit(s1); // you cannot do it - here exception will be thrown
you will surely recieve an exception:
java.lang.IllegalArgumentException: Attempting to edit an EntityProxy previously edited by another RequestContext
You may run into this problem in situations where you have a bean, but you have no track of request context which has created or edited the bean in some previous method call. In this situation you must save the previous requestContext somewhere, or send it along with the entity to the point of interest. The best solution may be to create some special layer which holds currently used request.
Trying to reuse a Request Context which has already been fired.
You can use a request context to create and edit many different entities (also of a different type). You can also accumulate the methods which should be fired. But what you cannot do is to try to use it twice to fire a request. If you have created a request and call the fire() method on it, you cannot do it again. If you do you will get: java.lang.IllegalStateException:A request is already in progress exception.
The solution is to simply create a new requestContext.
This was caused by not using the same EntityManager on the server.

What is the difference between getDefaultInstance() and getInstance() in Session class?

What is the difference between Session.getDefaultInstance(props, authenticator) and getInstance(props, authenticator)? In general, when will you choose one over the other?
I also read Java doc on getDefaultInstance(props, authenticator), but still couldn't able to make out the difference distinctly/clearly.
Hope experts can help me in understanding this better.
UPDATE: Actual reason that triggered to ask this question is: We've used Session.getDefaultInstance() method in some places within our web-based application. Sometimes, it throws java.lang.SecurityException: Access to default session denied, on quick googling, it suggested to use Session.getInstance() method instead. Hence, when one would choose one over the other?
If you read the documentation, you will see that
getDefaultInstance
Get the default Session object. If a default has not yet been setup, a new Session object is created and installed as the default.
Therefore, if one does not already exist, it call getInstance()
getInstance
Get a new Session object.
So, a new session object is created, regardless of whether one already exists.
FAQ says: https://javaee.github.io/javamail/FAQ#getdefaultinstance
Q: When should I use Session.getDefaultInstance and when should I
use Session.getInstance?
A: Almost all code should use Session.getInstance. The
Session.getDefaultInstance method creates a new Session the first
time it's called, using the Properties that are passed. Subsequent
calls will return that original Session and ignore any Properties you
pass in. If you want to create different Sessions with different
properties, Session.getDefaultInstance won't do that. If some other
code in the same JVM (e.g., in the same app server) has already
created the default Session with their properties, you may end up
using their Session and your properties will be ignored. This often
explains why your property settings seem to be ignored. Always use
Session.getInstance to avoid this problem.
Cause
This error is raised in the getDefaultInstance method in javax.mail.Session.java. According to this source code, this error occures when the default session object is already initialized, but authenticator instance is renewed or changed, or the class loader of the default session object is different from the argument authentificator's. Maybe the java source code using the default session instance of the java mail is recompiled and reloaded, or duplicate javamail class libraries are included into the Classpath of the environment.
it gives proper solution
javax.mail.Session.java file
public static synchronized Session getDefaultInstance(Properties props,
Authenticator authenticator) {
if (defaultSession == null)
defaultSession = new Session(props, authenticator);
else {
// have to check whether caller is allowed to see default session
if (defaultSession.authenticator == authenticator)
; // either same object or both null, either way OK
else if (defaultSession.authenticator != null &&
authenticator != null &&
defaultSession.authenticator.getClass().getClassLoader() ==
authenticator.getClass().getClassLoader())
; // both objects came from the same class loader, OK
else
// anything else is not allowed
throw new SecurityException("Access to default session denied");
}
return defaultSession;
}
For me, it was very important to use getInstance() instead of getDefaultInstance().
Because after mail session properties was changed, mail session still was storing old properties.
So getDefaultInstance() - it is looks like Singleton.
As docs said:
Note also that the Properties object is used only the first time this method is called, when a new Session object is created. Subsequent calls return the Session object that was created by the first call, and ignore the passed Properties object. Use the getInstance method to get a new Session object every time the method is called.

Categories