-
Notifications
You must be signed in to change notification settings - Fork 24.8k
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
jar hell in test classpath when running with JDK 1.8.0_66 on OS X (ant-javafx.jar, packager.jar) #14348
Comments
You have to fix your IDE config: #13465 |
Thanks. I removed "ant-javafx.jar" from the configured JRE classpath, works now. By the way, I wouldn't be surprised if you guys got more bug reports about this, because that's really weird (and the first time a library forced me to do that). |
Yeah, I suspect we will. Jarhell checks are too useful to give up though. I could see some extra help on these checks because they are much more
|
Everyone loves intellij, but nobody submits bugs to them for their clearly broken configuration. So I think its good if it confuses people, at some point it will encourage someone to fix the damn thing. I don't care about intellij, so it will not be me :) |
FYI same config works here flawlessly
|
@jprante That is because java (which bin/elasticsearch invokes) does not just put all of its jars in jdk and jre onto the bootclasspath. Intellij does, which is wrong. |
After some digging, I found this error in IntelliJ when selecting "Run" from the "Run" menu with the green triangle. What a strange way to start ES. It's not the boot class path, but the ordinary class path, which can be configured in "File -> Project Structure -> SDKs -> 1.8 -> Classpath". After editing configuration in Run>Edit configurations by setting VM options to How good that I'm used to console and Maven/Gradle, which IntelliJ supports very well. |
I have been trying to upgrade to elasticsearch 2.0, but the jar hell check is preventing me from doing so. From #13404, it seems that there are no plans to make it optional. However, I fail to see how it is possible to write tests using ESIntegTestCase in complex environment with the jar hell check enabled. In production I am usually deploying an uber jar, so everything works fine, since only one instance of a class goes in the flattened jar. But when running tests from maven, there isn't much I can do to avoid the jar hell, because the duplicated classes are in the dependency jars and the classloader is deciding at runtime which class to pick (as maven shade, which I use to build the uber jar, has decided offline). It seems that others in stackoverflow are having the same problem: http://stackoverflow.com/questions/33975807/elasticsearch-jar-hell-error. I used maven duplicate finder plugin to take a deep look in my duplicated jars to see what I could do, and although I could get rid of many of them, there are still some that seem impossible to fix. See below just for a glimpse of the problem:
Unfortunately, the reality is that upstream dependencies can be packaged in some crazy ways (sometimes for good reasons, sometimes not), and as far as I know, when in maven or intellij, different from deploy jars where I can use maven-shade or others, there isn't an "offline" way for me to tell the system how to get rid of the jar hell. After struggling this for quite some time now, the only way I out I see is to keep my own locally hacked elasticsearch, which is a solution I really don't like. Any other suggestions on how to work around this? If there is a true solution, I will be happy to hear, but right now I have 45 dependencies contributing to the jar hell, and I have no idea how to fix them. |
@bonitao I think you should take one step back and take a fresh breath. Wow, ES gives you the opportunity to clean up the dependencies of your project. Are you authoring a plugin? Or do you just need an embedded ES client? Beside wrestling with Maven, you could use Gradle for your project. There is a learning curve but the classpath configuration abilities are more flexible than in Maven. The ES team is switching to Gradle (again) because Maven is not flexible enough. For an example, see my integration test at https://github.com/jprante/elasticsearch-langdetect/blob/master/build.gradle which can test plugin loading- it does not require the ES test framework. Before thinking about a "hacked" Elasticsearch (which is a good thing), you could also try to just change the Elasticsearch build. From above it seems Google Guava has conflict with Spark. So it may be an alternative to shadow dependencides, either in your project, or in Spark, or in Elasticsearch. For example, there is a great Gradle shadow plugin at https://github.com/johnrengelman/shadow |
Hi @jprante, Thanks for the response. A month ago, when first tried to upgrade to ES 2.x, I have actually tried to approach this as you said: as an opportunity to clean up my dependencies. But it did not work out, and I do not believe it will. Let me try to explain why. I am not authoring a plugin. I am building a restful service that has an embedded ES client and an extract/load/transform pipeline, which also talks with ES. The code does a bunch of things, like doing search queries, doing snapshot/restores through the admin api, and doing bulk indexing with elasticsearch-hadoop-mr. This all works with ES 1.7.x, and from what I have seen, it also works in ES 2.x after I build an uber jar. The only thing that fails are my unit tests in ES 2.x, because in the test environment my classpath is built from the individual dependency jars. The code is built with maven, but I also have a SBT setup for it. I have a passing knowledge of gradle, but as I understand, none of these tools really support the idea of creating a test classpath by unzipping and manipulating dependencies jars. Yes, they all have tricks like the one you did in https://github.com/jprante/elasticsearch-langdetect/blob/master/build.gradle#L121 to remove full jars from the classpath, but not for manipulating the contents of the individual classpaths for tests. It is of course possible, after all, both the maven shade plugin and the gradle shadow plugin you linked, solve that exact problem. But these are tied to the release steps of the build, and as far as I know, there is not a natural way to run my unit tests with a classpath pointing solely to an uber jar. So, all the jar hell check is buying is forcing me into moving my unit tests into integration tests, and forcing the integration tests to work out of the flat jar (which I still need to figure out how to do). As for fixing the jar hell in the dependencies, it is just not possible. I have already fixed many simple cases, like common-beanutils and netty, which is brought as a uber jar and individual deps in my build, and for smaller libraries, I have worked on upstream fixes to their pom, but I still have dozens of conflicts (all easily seen with duplicate finder), and some are really beyond my league. I would love to see anyone that has been able to run unit tests with ES 2.x and spark together. Direct shadowing is of no help here, because the libraries are being used directly in the tests. I would need to shadow guava within spark, and depend on the resulting jar instead of the original spark libraries. And the spark issue is just one of many. For example, hadoop has some fake conflicts with itself:
And so does spark:
And scala-lang bundles stuff it probably shouldn't:
And my dependencies bring conflicting opencsv versions:
So, I will need to solve each one of those to be able to run elasticsearch tests, even though I already have a solution for production, through the creation of uber jar. So, all I really need is a flag to disable the jar hell check in unit tests. With that flag, I could even choose to run the tests again in the integration phase with the flattened jar, but that is later in the development cycle, and slower. I hope that exposition of the problem helps. ES is a great product, and I will definitively hack the source to get my tests to run if needed, but it seems to me that many people will face similar issues, and it would be best to leave a system property toggle for when fixing the jar hell is not feasible. Again, in production there is nothing to fix if you are running a flattened jar (damage is already done), and if I understand it right, people not running tests won't even hit the check. |
@bonitao I know this is the wrong place to discuss further because it may be going off-topic. You can email me privately (see my github profile). The only thing I like to understand is why it is not possible to assemble a cleaned up uberjar of your project by exploding all the various messy dependencies you have mentioned here, except the ES dependencies, and pass the uberjar later to the classpath of an ES integration test. |
@jprante I would really appreciate if you could continue the discussion publicly. I'm facing the same issues as @bonitao does (especially the issue with org.apache.spark.unused.UnusedStubClass) and I would be glad to see whether there is a good down-to-earth solution for the problem. package org.elasticsearch.bootstrap; public class BootstrapForTesting { public static void ensureInitialized(){} } which basically means I'm fighting jar hell fighting with jar hell. Far from ideal. |
@jprante I'm facing the same issue as @bonitao and @cff3 (as are others looking at other issues raised on this project) and its taking a lot of time to sort out and all we are trying to do is write an integration test. Surely the obvious thing is to have a system property to disable the check with a warning if duplicates exist. After all there is no guarantee that the duplicate class may actually be used by the code. The default can still be crash and burn. And if even if a duplicate was used and the "wrong" class was loaded isn't it a case of caveat emptor ("let the buyer beware" ) ? |
@PeterLappo The test framework is meant to check elasticsearch works, and we have done a lot of work to ensure we know exactly which classes are being loaded (ie the jarhell work). If you are just using elasticsearch as a service, a much better integration test is using a real elasticsearch node (and the test setup already allows this, see the many QA tests or integration tests for plugins in the elasticsearch repo, and the discussion in #11932). If you are embedding elasticsearch, then it is better for you to have your own test base classes which initializes an embedded node as you would (and constructing a Node directly does not do a jarhell check). |
I think 2 years ago I would have agreed with you. Now after all the things that i have seen working on es core for a long time I can tell you any kind of opt-out and or leniency is the root of all evil. The only thing that I am considering as a temporary solution until we have a good and released test-fixture for a real integ test is to add an opt-out to the jar hell check in the test bootstrap. On the real node I am sorry we won't go there to protect us and others from even getting to the point where this can be trouble. |
@rjernst @s1monw I have some client code written with Jest that writes to ES and I want to create a test that proves my code works. I have tests working but they relied on a local instance of ES running which is not ideal as I'd need to ensure the tests run on integration servers or other peoples machines. Our code is not so easy to clean as there are several conflicts that JarHell detects which are beyond my control, e.g. sl4j in dependent libraries. So I would like to spin up an instance of ES and test my Jest client logic and verify the data exists as I expect in ES. At the end of the test I then want to close down ES and clean up any data. Ideally I want
Obviously I can start a ES in a separate process during my test and do all the setup myself but I was hoping something may exist already and maybe an example that I can copy to get me started? |
@PeterLappo Having external services for integration tests is exactly the point of us adding test fixtures (in master). See #15561. For 2.x, you can look at how the client tests start an ES cluster. |
Thanks will take a look |
I'm also facing the same problem as @bonitao. Is there any solution - other than modifying the elasticsearch source code - to this issue? Your help will be much appreciated. |
We gave up and wrote a script that started a ES instance, ran the tests and then shutdown ES
|
Echoing what others have said here - we build an uber jar of ES with some shaded/relocated dependencies, mostly due to version conflicts between ES and our project's dependencies. We would LOVE to be able to use ESIntegTestCase to test our mappings, transforms, index requests, and queries, but at the moment are unable to do so without shading the entire test-jar, which raises a whole host of other issues. @s1monw any chance of adding that opt-out to the jar hell check in the test bootstrap soon? |
I stumbled across this today, and am now also fighting jar hell in transient dependencies. I get the sentiment re: jar hell, I really do, and I want to be on board. At the moment, I can't use elasticsearch with Apache Storm and Flux, because Flux has commons-cli as a dependency, and is "overriding" class behaviour with it's own jar hell a la @cff3:
I can't do anything about this. It's holding up my development. How would others solve this? |
@ndtreviv May be you could find some ideas here: https://www.elastic.co/blog/to-shade-or-not-to-shade. |
Trying to run a test that extends
ESIntegTestCase
with Elasticsearch 2.0.0, getting this:Not sure I can do much about that.
The text was updated successfully, but these errors were encountered: