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

Custom ClassLoader support #626

Closed
patka opened this issue Oct 15, 2013 · 3 comments
Closed

Custom ClassLoader support #626

patka opened this issue Oct 15, 2013 · 3 comments
Milestone

Comments

@patka
Copy link

patka commented Oct 15, 2013

I am developing a plugin for the TeamCity CI server. I want to store some data in an H2 database and I want to use flyway for the migration between different versions. I included Flyway as a spring bean and I therefore the migration is done during the server startup within a Tomcat container.

The problem I have is that flyway cannot find its own initial script createMetaDataTable.sql. It is failing with a FlywayException "Unable to obtain inputstream..."

I investigated this and it is a ClassLoader issue. When

ClassPathResource.loadAsString()

is called, I have the following ClassLoader hierarchie:

  • Application ClassLoader
  • org.apache.catalina.loader.StandardClassLoader
  • org.apache.catalina.loader.WebAppClassLoader
  • jetbrains.buildServer.plugins.classLoaders.PluginsSharedClassLoader

The PluginsSharedClassLoader is the one that has the flyway-core.jar in its classpath because the TeamCity plugins are located in a directory in the home directory of the user executing the server and therefore outside of the webapp folder. I guess, that is why they use a new ClassLoader.

ClassPathResource however uses

Thread.currentThread().getContextClassLoader()

to retrieve the ClassLoader which in my case is org.apache.catalina.loader.WebAppClassLoader. This makes sense because web containers are supposed to set the applications ClassLoader on the thread, if I remember correctly. However this means, that in every case, that a web application defines its own ClassLoader in which flyway will be executed (like for plugins as in my case) it will not work correctly.

If I instead use

getClass().getClassLoader()

I get a reference to the PluginsSharedClassLoader and everything works fine.

Is there a specific reason why the ClassLoader is obtained from the current thread? Otherwise I would look into providing a patch for this. There are currently two CommandLine tests failing with this solution but I think I can find the reason for this.

I tested this with the current trunk and release 2.2.1.

My environment is:
JDK 7
Mac OS 10.8.6
Idea IntelliJ 12

Greets,
Patrick

@patka
Copy link
Author

patka commented Oct 16, 2013

Ok, now I understand why the class loading is implemented like this. It is required to add the script locations in the command line application. Well, I don't know if this plugin problem is something you want to cover with Flyway. I guess I can also write a flyway wrapper and set the correct ClassLoader in there and by this work around this issue.

Anyway, if you want to tackle this issue, I would be glad to help.

Greets,
Patrick

@axelfontaine
Copy link
Contributor

Hi Patrick,

one thing I could consider would be to add a Flyway.setClassLoader() method. The default classloader would still be the context classloader, but this way you could overwrite it.

Pull request welcome.

Cheers
Axel

@patka
Copy link
Author

patka commented Mar 22, 2014

Hi Alex,

sorry that I did not help out on this one although I said I want to. I
became a father recently and did not have the time to dig into this
issue. But anyway, thanks for taking care of it!

Greets,
Patrick

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

2 participants