New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LoadTimeWeaving not working properly in Websphere [SPR-9857] #14490
Comments
Patrick McCabe commented I am running Spring GA 3.1.2, using Websphere 7.0.0.23, with the JPA2 feature pack installed, which uses OpenJPA 2.0.2-SNAPSHOT What I am seeing appears to be an issue with load time weaving of JPA entities when the entity is declared as a return paramater of a method inside a class which has an auto injected persistence context or persistence unit. The load order of the classes also changes this behaviour as shown below. I've created a very simple application which demonstrates this issue. My Spring Config as follows.
I have a single Entity to manage as follows.
Now, here is where the funny stuff starts. I have the following repository defined.
When I try to run this code, I get a warning, then an exception from OpenJPA saying the entity has not been enhanced. Seems strange, since everything is configured correctly.
method from both the implementation, as well as the interface, the code runs correctly. So basically, when I introduce a method with an Entity as the return paramater, the load time weaving fails to enhance it. Whats even more interesting is that if I create a second repository with just single method as below. AND this class gets loaded FIRST. Then the previous repository which had given me errors now works correctly. So there is definately someting funny going on with the load order of the classes
|
Patrick McCabe commented After doing some debugging, it is apparent that in the failure case, the entity class is being loaded at deploy time prior to having the proper class transformer created.
I can see that the AspectJWeavingEnabler#AspectJClassBypassingClassFileTransformer transformer is initially applied. I can see the Person entity going through this transformer. After all classes are loaded, then the proper PersistenceProviderImpl$ClassTransformer is applied. Obviously at this point it is too late to transform the entity class. Using the alternate configuration of specifying the transformer directly in the LocalContainerEntityManagerFactoryBean similarly fails, as the transformer is also applied after the entity class is loaded. |
Patrick McCabe commented I think I've tracked down the root of this problem. This method
uses
to inspect methods of all spring beans. Since the Person entity is declared in my interface, that entity gets loaded at this point in time. The problem is that at this point
has not yet been called. It is this operation that adds the proper ClassTransformer required to transform the JPA entity classes for OpenJPA. Since the Person class is loaded before the correct Transformer has been applied, I receive the Entity not enhanced error. This also explains the peculiar behaviour I was seeing when I added a second repository. After the first repository bean was loaded with no reference to any JPA entities in the interace, the EntityManager was created, resulting in the ClassTransormer being applied. When it comes to load the second repository, which previously caused issues, it works because the proper ClassTransformer is now in place. As a fix, we need to ensure that the EntityManager is initialized prior to calling PersistenceAnnotationBeanPostProcessor.findPersistenceMetadata. I'm not sure where the best place to do this would be yet. Hopefully some of you Spring guys could have a look. If I have time, I will continue to investigate. |
Juergen Hoeller commented This definitely looks like some side effect of the class loading order. We're using a temporary ClassLoader exactly in order to avoid such effects, but I suppose we're missing some specific case there. Note that when deploying to WebSphere, you could also let WebSphere manage the persistence units and obtain the EntityManagerFactory references via JNDI (jee:jndi-lookup elements in your Spring config). This way of deployment should be documented in the server manuals since it is basically the default EE way of handling persistence units. Spring can then take it from there, managing the persistence contexts, transactions, etc the usual way. See Spring's PersistenceAnnotationBeanPostProcessor javadoc for some details. Juergen |
Juergen Hoeller commented As for the runtime effects here, thanks for digging into this - your comments up there are very valuable! We indeed need to make sure that the LocalContainerEntityManagerFactoryBeans in the context are being initialized eagerly before any repository beans that might use them. This happens quite explicitly when using standard bean references (<property>, <constructor-arg>) but unfortunately is being applied more implicitly when using Does it make a difference whether your LocalContainerEntityManagerFactoryBean definition comes before the <context:component-scan base-package="test"/> instruction? The order could be significant there since aside from inter-bean dependencies, the container will initalize beans in the order of definition in the context. Putting the LocalContainerEntityManagerFactoryBean first should turn it into the first bean getting initalized, possibly making the arrangement work as well. Juergen |
Juergen Hoeller commented I've temporarily added early initialization of LoadTimeWeaverAware beans before regular beans are being considered, which should help in bootstrapping LocalContainerEntityManagerFactoryBeans before any repository beans - independent from the order of definition. It would be great to know whether putting your LocalContainerEntityManagerFactoryBean definition before your component-scan instruction (or explicit repository bean definition) actually helps in your scenario. That would validate the fix above. Juergen |
Patrick McCabe commented Hi Juergen I have validated that placing the LocalContainerEntityManagerFactoryBean definition before <context:component-scan base-package="test"/> does fix the problem. This would seem to validate your fix. |
Patrick McCabe commented If you a build with this fix included, I would be happy to validate it for you. |
Juergen Hoeller commented Good to hear that the LocalContainerEntityManagerFactoryBean reordering helps there, Patrick! The algorithm I'm using now is pretty straightforward, since LoadTimeWeaverAware is a perfect indicator for beans potentially registering class transformers. I'm confident that it will do the trick. I'll make another 3.1.3 snapshot available in about an hour. Would be great if you could give it a try then... Juergen |
Juergen Hoeller commented Pushed to the repo now. The snapshot should be available once the CI build (3.1.x #158) passed. Juergen |
Patrick McCabe commented Hi Juergen I see that the recent build has passed all tests, and should be available for download. Forgive my ignorance, but where exactly do I go to download these releases ? Thanks |
Patrick McCabe opened SPR-9857 and commented
Affects: 3.1.2
Issue Links:
@Entity
objects are not enhanced by the load time weaver in certain situationsThe text was updated successfully, but these errors were encountered: