Skip to content
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

Stripes ActionBeans not found when jar is built as 'executable' #4310

Closed
jbcpollak opened this issue Oct 27, 2015 · 13 comments
Closed

Stripes ActionBeans not found when jar is built as 'executable' #4310

jbcpollak opened this issue Oct 27, 2015 · 13 comments

Comments

@jbcpollak
Copy link

This issue seems to be very similar to #3413.

When we run our project from an IDE (Eclipse) everything works fine and both Ebeans and Stripes are able to scan our packages for the classes they need.

When we build as a jar with configuration in our pom file:

        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>1.3.0.M2</version>
            <configuration>
                <executable>true</executable>
            </configuration>
        </plugin>

Ebeans fails to find classes annotated with @Entity classes and Stripes fails to find classes that implement ActionBean.

When I remove the <executable> tag as #3413 suggests, there is no change.

I've also tried downgrading to the 1.2.7 version of the plugin with no change.

@snicoll
Copy link
Member

snicoll commented Oct 27, 2015

Then it's not similar to #3413. I don't know what Ebeans and Stripes are but maybe they need the content to be unpacked in the jar somehow. Have you seen this option? Can you try it on your project?

@snicoll snicoll added the status: waiting-for-feedback We need additional information before we can continue label Oct 27, 2015
@jbcpollak
Copy link
Author

Sorry I wasn't clear, its our own classes, already unpacked in the jar,
that can't be scanned.

Ebeans is an ORM layer, its used by the Play Framework but we use it
separately.

Stripes is a web framework like Struts or Spring MVC.

Both scan your own code for classes you've written and load them.

This worked fine when our code was packages as a war or when we run
unpacked on the commandline, or from an IDE, but fail when packed into a
Spring Boot jar.

On Tue, Oct 27, 2015, 3:53 AM Stéphane Nicoll [email protected]
wrote:

Then it's not similar to #3413
#3413. I don't
know what Ebeans and Stripes are but maybe they need the content to be
unpacked in the jar somehow. Have you seen this option
http://docs.spring.io/spring-boot/docs/1.3.0.BUILD-SNAPSHOT/maven-plugin/repackage-mojo.html#requiresUnpack
?


Reply to this email directly or view it on GitHub
#4310 (comment)
.

@wilkinsona
Copy link
Member

@jbcpollak Can you provide a small sample that reproduces the problem please?

@jbcpollak
Copy link
Author

@wilkinsona Please see here: https://github.com/AssuredLabor/spring-boot-issue-4310

the readme for the project is included below for reference and to clarify the problem.

I noticed the classloader changes between the two running modes, I assume that is the problem.

Code works when run from .class files

First run the project from Maven:

mvn spring-boot:run

In the logs you should see these lines:

2015-10-27 17:23:14,862 [org.example.SpringBoot4310App.main()] c.a.e.s.c.BootupClassPathSearch INFO : Classpath search hits in jars[] pkgs[org.example.beans]  searchTime[26]
2015-10-27 17:23:15,220 [org.example.SpringBoot4310App.main()] c.a.e.s.c.DefaultServerFactory WARN : DataSource [db] has autoCommit defaulting to true!
2015-10-27 17:23:15,239 [org.example.SpringBoot4310App.main()] c.a.e.s.c.DefaultServerFactory INFO : DatabasePlatform name:db platform:h2
2015-10-27 17:23:15,338 [org.example.SpringBoot4310App.main()] c.a.e.a.ClassLoadContext DEBUG: Context and Caller ClassLoader's same instance of java.net.URLClassLoader
2015-10-27 17:23:15,400 [org.example.SpringBoot4310App.main()] c.a.e.s.d.BeanDescriptorManager DEBUG: BeanPersistControllers[0] BeanFinders[0] BeanPersistListeners[0] BeanQueryAdapters[0]
2015-10-27 17:23:15,489 [org.example.SpringBoot4310App.main()] c.a.e.s.d.BeanDescriptorManager INFO : Entities enhanced[1]

The first and last lines above indicate Ebeans was able to scan for the class org.example.beans.User

When you visit http://localhost:8080/page/welcome you will see the text Welcome!

Code is broken when run as a JAR

Now run the following commands:

mvn package
java -jar target/spring-boot-issue-4310-0.0.1-SNAPSHOT.jar

In the logs you will see:

2015-10-27 17:26:55,536 [main] c.a.e.s.u.ClassPathSearch WARN : No Entities found in ClassPath using ClassPathReader [com.avaje.ebeaninternal.server.util.DefaultClassPathReader@2e166a83] Classpath Searched[[jar
2015-10-27 17:26:55,536 [main] c.a.e.s.c.BootupClassPathSearch INFO : Classpath search hits in jars[] pkgs[]  searchTime[12]
2015-10-27 17:26:55,737 [main] c.a.e.s.c.DefaultServerFactory WARN : DataSource [db] has autoCommit defaulting to true!
2015-10-27 17:26:55,751 [main] c.a.e.s.c.DefaultServerFactory INFO : DatabasePlatform name:db platform:h2
2015-10-27 17:26:55,790 [main] c.a.e.a.ClassLoadContext DEBUG: Context and Caller ClassLoader's same instance of org.springframework.boot.loader.LaunchedURLClassLoader
2015-10-27 17:26:55,827 [main] c.a.e.s.d.BeanDescriptorManager DEBUG: BeanPersistControllers[0] BeanFinders[0] BeanPersistListeners[0] BeanQueryAdapters[0]
2015-10-27 17:26:55,827 [main] c.a.e.s.d.BeanDescriptorManager INFO : Entities enhanced[0]

The first and last lines indicate Ebeans was unable to find org.example.User

When you visit http://localhost:8080/page/welcome you will get a 500 error in the browser and there will be an exception in your logs:

net.sourceforge.stripes.exception.ActionBeanNotFoundException: Could not locate an ActionBean that is bound to the URL [/page/error]. 
Commons reasons for this include mis-matched URLs and forgetting to to implement ActionBean in your class. 
Registered ActionBeans are: {/controller/DefaultView.action/=class net.sourceforge.stripes.controller.DefaultViewActionBean, 
/controller/DefaultView.action=class net.sourceforge.stripes.controller.DefaultViewActionBean}

Notice the WelcomeBean and ErrorBean classes are not listed as registered ActionBeans.

@jbcpollak
Copy link
Author

I debugged into Stripes a bit and found they use the first four bytes of the resource to verify it is a JAR file. So with <executable>true</executable> in your pom.xml, Stripes will fail to register the ActionBeans, and you will get this error. See this code in Default VFS. Is this a Stripes or Spring issue? I assume Spring can't really do anything about this.

With executable set to false, Stripes will register the ActionBeans, but when the ActionBean forwards to a JSP, the JSPs can't be resolved.

I followed the jsp limitiations advice here and example here. In short, if I put the jsps in /src/main/webapp/WEB-INF/jsp, when I run as unpacked classes tomcat can't resolve them, and I can't verify if they would work in war format because Stripes won't load the action beans in either war or executable war format, because the magic bytes don't match.

In summary, Stripes is compatible with Spring-Boot only if there is a way to get the JSPs working, and you can live with executable=false.

Any advice on getting the JSPs working would be appreciated.

@jbcpollak jbcpollak changed the title Ebeans Entities and Stripes ActionBeans not found when jar is built as 'executable' Stripes ActionBeans not found when jar is built as 'executable' Oct 29, 2015
@jbcpollak
Copy link
Author

Ebeans version 6.10.1 was released today which supports Spring-Boot jars (even with <executable>true</executable>, so I've renamed this issue to focus on Stripes.

@snicoll snicoll removed the status: waiting-for-feedback We need additional information before we can continue label Oct 29, 2015
@snicoll
Copy link
Member

snicoll commented Oct 29, 2015

Shouldn't you report that issue to the Stripes issue tracker instead please? As for the JSP support, this sounds like a totally unrelated issue so let's not discuss that here please.

@wilkinsona
Copy link
Member

Is this a Stripes or Spring issue? I assume Spring can't really do anything about this.

That's a Stripes issue. If you want to continue to use <executable>true</executable>, you might want to explore registering a custom VFS by passing it to VFS.addImplClass(Class). A DefaultVFS subclass that overrides isJar would probably do the trick.

@wilkinsona
Copy link
Member

I can't verify if they would work in war format because Stripes won't load the action beans in either war or executable war format, because the magic bytes don't match.

It's not the magic bytes that are a problem here, it's Stripes assuming that the archive's name will end with .jar. You can work around the problem by providing your own VFS implementation:

import java.net.MalformedURLException;
import java.net.URL;

import org.springframework.util.ResourceUtils;

import net.sourceforge.stripes.vfs.DefaultVFS;

public class SpringBootVfs extends DefaultVFS {

    @Override
    protected URL findJarForResource(URL url) throws MalformedURLException {
        return ResourceUtils.extractJarFileURL(url);
    }

}

This seems to work with an <executable>false</executable> .war file run with java -jar. Unfortunately, it then exposes some limitations in Ebeans' classpath scanning, even with 6.10.1. You could probably work around that with a custom ClassPathSearchService.

In short, I don't think there's anything in Spring Boot that's stopping this from working. I've offered some help to improve Ebeans' classpath scanning. You may want to open a Stripes issue to remove the need for the custom VFS implementation.

@jbcpollak
Copy link
Author

Agreed - This is a Stripes problem, combined with the JSP problem. Is this the best place to track the JSP issue?

@wilkinsona - Thanks for the advice, I'll try out the Stripes workaround, but its pointless until the JSPs are fixed.

@wilkinsona
Copy link
Member

With some changes to Stripes and EBeans there won't be a JSP problem as you'll be able to use a .war file run with java -jar.

@jbcpollak
Copy link
Author

Thanks, I'll give it a shot

@jbcpollak
Copy link
Author

@wilkinsona - I don't want to drag this thread on here, but for anyone else who might come across this ResourceUtils.extractJarFileURL() is not a complete drop in solution - it doesn't work when run unpacked from .class files. Also, ResourceUtils doesn't seem to consider .war files to be jar files.

I create an issue in Stripes and will continue the conversation there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants