Open jbcpollak opened 9 years ago
@wilkinsona - Stripes cannot load the ActionBeans when compiled as war because it is path-matching here, and it is trying to compare (for example):
/org/example/action/
with what it found in the war:
/WEB-INF/classes/org/example/action/WelcomeBean.class
What is the proper way to handle that? Should the code be augmented to ignore /WEB-INF/classes/
, or is there a simpler mechanism?
HI Joshua, can you use simple exploded war?
2015-10-29 13:48 GMT-05:00 Joshua Chaitin-Pollak notifications@github.com:
@wilkinsona https://github.com/wilkinsona - Stripes cannot load the ActionBeans when compiled as war because it is path-matching here https://github.com/StripesFramework/stripes/blob/master/stripes/src/main/java/net/sourceforge/stripes/vfs/DefaultVFS.java#L177-L180, and it is trying to compare (for example):
/org/example/action/
with what it found in the war:
/WEB-INF/classes/org/example/action/WelcomeBean.class
What is the proper way to handle that? Should the code be augmented to ignore /WEB-INF/classes/, or is there a simpler mechanism?
— Reply to this email directly or view it on GitHub https://github.com/StripesFramework/stripes/issues/35#issuecomment-152284551 .
Here I found something related to exploded jar in Spring boot
2015-10-29 14:12 GMT-05:00 Nestor Hernandez iluvtr@gmail.com:
HI Joshua, can you use simple exploded war?
2015-10-29 13:48 GMT-05:00 Joshua Chaitin-Pollak <notifications@github.com
:
@wilkinsona https://github.com/wilkinsona - Stripes cannot load the ActionBeans when compiled as war because it is path-matching here https://github.com/StripesFramework/stripes/blob/master/stripes/src/main/java/net/sourceforge/stripes/vfs/DefaultVFS.java#L177-L180, and it is trying to compare (for example):
/org/example/action/
with what it found in the war:
/WEB-INF/classes/org/example/action/WelcomeBean.class
What is the proper way to handle that? Should the code be augmented to ignore /WEB-INF/classes/, or is there a simpler mechanism?
— Reply to this email directly or view it on GitHub https://github.com/StripesFramework/stripes/issues/35#issuecomment-152284551 .
IMO, it should be using each URL that's on the classpath as a root for its search. One of those entries points to WEB-INF/classes
inside the war file.
@iluvtr @wilkinsona - I'll check out both suggestions.
My other thought was to just move our ActionBeans into a separate module which the .war depends on. I suspect that would work. It would get odd with the ActionBeans in a jar and the jsps in the .war, but I could deal with that.
I seem to have gotten this working by using a multi-module setup. I moved the ActionBeans to a dependency jar, and left the JSPs in the webapp. I still need to use the work-around SpringBootVfs class and build the application as a war because of Spring-Boot issues, but it seems to work.
You can see this branch for this solution: https://github.com/AssuredLabor/spring-boot-issue-4310/tree/multi-module
I consider this a work-around though, not a long term solution.
@jbcpollak
I have looked into your demo project.
The .jar generated with mvn package
cannot be extracted using jar xvf
command (I'm using JDK 1.8.0_60).
It can be extracted using unzip -q
with a warning "5124 extra bytes at beginning or within zipfile" and I see some shell script code at the beginning of the file in binary editor [1].
So, I think creating a custom VFS is the proper way to handle this JAR file.
FYI, I recently investigated a Spring-Boot related issue in MyBatis [2] regarding nested JARs and concluded that it should be handled by a custom VFS implementation.
[1] If I changed the Spring-Boot version to 1.2.4.RELEASE, mvn package
generates a regular JAR archive and WelcomeBean is registered on startup.
[2] MyBatis uses the VFS mechanism ported from Stripes.
@harawata - The problem with the jar as the project is setup is that Spring is appending an init.d style start-stop bash script to the start of the jar file. You can disable that by changing the following line in the Spring-Boot plugin to false:
<executable>false</executable>
However, even when I do that, the Action Beans still aren't loaded with the latest version of Spring-Boot.
Do you know if there is any intention to provide a SpringBoot VFS standard in Stripes or MyBatis? It seems that since Spring-Boot is rapidly gaining traction, this would be a good idea.
Notice my multi-module workaround branch provides a VFS but that there were still problems.
Also keep in mind that due to a Spring error, you need to build a .war file, not a .jar file so that the JSPs can be processed correctly. This has an impact on the VFS operation as well.
Hi @jbcpollak
Do you know if there is any intention to provide a SpringBoot VFS standard in Stripes or MyBatis?
Not that I know of.
It seems that since Spring-Boot is rapidly gaining traction, this would be a good idea.
I agree. The difficulty is that Spring-Boot can generate various forms of JAR/WAR (executable or not, embedded, etc.) and users would expect the Spring-Boot VFS to handle all the variations.
Annotation scanning is (starting from JEE6) a service that the container provides. I think Stripes should leverage this instead of trying to implement proprietary VFSs for all supported app servers...
http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContainerInitializer.html
Just pushed a preview of how we could leverage ServletContextInitializer
in order to "scan" the classpath for us. This seems to work fine on the examples webapp (all tests are green).
Thing is, it requires java8 and Servlet3... I think it's time to upgrade.
I don't see how we can remove VFS support. I worked with someone in IRC to get a Stripes-based SpringBoot application working using myBatis' SpringBootExecutableJarVFS. It required no changes at all. Just drop it right in. Everything worked fine. There is no real standard about what functionality "listResources" needs to provide from a classloader perspective. Especially when it comes to things like nested and/or encoded JAR files. In the case of the unit tests, we have no container-based unit tests around VFS support. Actually, SpringBoot would be a great way to actually create an executable suite of unit tests in Jenkins that run inside of a real container.
@rgrashel I think that person in IRC would have been me :) I have done some more testing since and found that the solution with the SpringBootExecutableJarVFS works while running the app with 'mvn spring-boot:run'.
However, after packaging the app and executing it the way it would be when deployed (eg. java -jar app.war), none of my ActionBeans are discovered. I'll be looking into this today.
That's what I'm talking about : trying to implement another VFS every time is a waste of time if you consider that this service can be provided by the container...
Are you using a servlet3 container ? Not sure what Spring Boot does, I'm not familiar with it.
@hanswesterbeek If you're using a Servlet3 container, could you please try the VFS-less approach I have commited ? I have tested it on Tomcat and Jetty and it seems to work just fine. It's only a draft at the moment, but it shows a way to bypass the VFS completely and rely on container-provided Classes.
@vankeisb Yes, Spring Boot uses an embedded Tomcat 8 so that should be fine.
I was looking at your commit but don't quite understand how I would use it as that initializer, or how it works. Maybe you can elaborate on it?
Initial investigation leads me to believe that this won't be easy, because the required META-INF/services/javax.servlet.ServletContainerInitializer file must be inside a jar.
Cool thanks for giving it a try.
Yep, it's initialized using a META-INF/services/javax.servlet.ServletContainerInitializer
file, with the class name net.sourceforge.stripes.init.StripesContainerInitializer
in it.
I'm adding this file (with the dir structure of course) to src/main/resources
in the app. It ends up packaged in the war (regular mvn build) :
WEB-INF/classes/META-INF/services/javax.servlet.ServletContainerInitializer
The war then runs in tomcat, with those kind of logs at startup :
12:40:21,737 INFO StripesContainerInitializer:47 - 99 classes loaded.
Tested with the stripes-examples webapp.
I've also tried to embed this file right in the stripes jar, but it didn't work. It only worked with the file present in the app's classes, not the dependent jars.
Btw the init code is quite ugly, the static and all, but we'll find a proper way to do this later.
What I don't get is that if this works, and the classes have indeed bean loaded, how would I take advantage of it? How do I make sure that Stripes finds my action beans?
I have modified ResolverUtil
so that this works.
It's basically here :
It will now look first for container-resolved classes (action beans, and all other Stripes "scannable" stuff). If it finds those, it completely bypasses the VFS : it simply looks in the list of classes provided by the container.
This means that if you define the ServletContainerInitializer in META-INF/services, then Stripes will take advantage of this instead of using VFS, which is now basically a "fallback" for those who don't use the container initializer, or for the Mock testing APIs.
Unfortunately Spring Boot does not honor the full EE-spec and will not invoke the ServletContainerInitializer. So while your solution would help people on newer appservers, it won't help users of Spring Boot.
See this issue: https://github.com/spring-projects/spring-boot/issues/321
Damnit.
Apparently they have an alternative of their own, but to be honest I don't have time to look into it at the moment. Also, I'm thinking that Spring has its own scanning mechanism. Maybe this could be leveraged instead of the VFS which is way too "low level" (the container can inject a Collection
Was worth a try anyway, thanks for helping out.
Hmmmm, out of curiosity, I took a glance. Check this out :
http://www.eclecticlogic.com/2014/09/01/classpath-scanning/
Seems pretty easy to write the same mechanism I wrote with the container initializer, but using this API in order to store the scanned Collection<Class>
, just like I did in my experiment. Definitely easier than a custom VFS :P
We ended up patching the SpringBootVfs that we were already using. It defers all searching to Spring's PathMatchingResourcePatternResolver and works. https://gist.github.com/hanswesterbeek/94c359b22c6fed6dff1c
Hello, we are no longer working on this project, but we did finally get it working. I'm not sure if its helpful, but here is a Gist ripped from our code showing how we plug the VFS into our App:
https://gist.github.com/jbcpollak/84b1d7c8c06854b1291a
I do like @hanswesterbeek solution to defer to Spring's resolver - that is a good approach.
Thanks a lot for this, folks. I'm going to ping the MyBatis guys to see if they are interested in this solution also. I also think using Spring's resolver is a lot more elegant because it doesn't require manual JAR logic. I've already spoken to the Spring-Boot team and they gave me a recommendation for a dependable piece of code to use within Stripes which allow it to "auto-detect" if it is running within a Spring-Boot environment. So that's all we'll need to pull this into the Stripes core.
Many thanks again, gents!
-- Rick
On Wed, Jan 13, 2016 at 10:42 AM, Joshua Chaitin-Pollak < notifications@github.com> wrote:
Hello, we are no longer working on this project, but we did finally get it working. I'm not sure if its helpful, but here is a Gist ripped from our code showing how we plug the VFS into our App:
https://gist.github.com/jbcpollak/84b1d7c8c06854b1291a
I do like @hanswesterbeek https://github.com/hanswesterbeek solution to defer to Spring's resolver - that is a good approach.
— Reply to this email directly or view it on GitHub https://github.com/StripesFramework/stripes/issues/35#issuecomment-171358203 .
@hanswesterbeek thanks for sharing, this definitely has to be integrated.
I still think VFS is obsolete and probably not the appropriate "level of abstraction" (using Class objects would be much easier)... but if we have good coverage (major fwks/ASs are supported) then I'm good with it.
Remi,
Can you come to IRC to discuss? I'm not really clear on why you think VFS is obsolete if there are containers which do not provide consistent expected classpath scanning using the Java resources classes within the core JDK.
-- Rick
On Wed, Jan 13, 2016 at 11:02 AM, Remi Vankeisbelck < notifications@github.com> wrote:
@hanswesterbeek https://github.com/hanswesterbeek thanks for sharing, this definitely has to be integrated.
I still think VFS is obsolete and probably not the appropriate "level of abstraction" (using Class objects would be much easier)... but if we have good coverage (major fwks/ASs are supported) then I'm good with it.
— Reply to this email directly or view it on GitHub https://github.com/StripesFramework/stripes/issues/35#issuecomment-171364587 .
One more thing, the impl I showed you does not take sub-packes into account. Working on that still...
Solved. This should be the one: https://gist.github.com/hanswesterbeek/94c359b22c6fed6dff1c
I am also under the impression that it performs quite a bit better than the one we had before.
Thank you for sharing, @hanswesterbeek ! May I assume your custom VFS is licensed under ASL v2.0 as Stripes is? We consider porting it to MyBatis-Spring-Boot project. (apology for a off-topic comment...couldn't get a reply on the gist)
Hello, I've been trying to track down problems between Spring-Boot and Stripes. Originally I thought it was a Spring-Boot issue, but it appears to be a problem with the Stripes VFS implementation.
I'm working through a workaround now, but wanted to create a note here about it. There is a also a demo project that shows the problems.