构建路径上的两个JAR具有相同的方法名称但具有不同的构造函数。如何指定使用哪种JAR方法?

时间:2014-01-08 19:38:48

标签: java eclipse jar stanford-nlp

我正在从几个不同的开源库构建工具。我的构建路径按以下顺序排列:

我的第一个JAR文件stanford-corenlp-3.3.0.jar包含一个名为edu.stanford.nlp.process的包,其中包含Morphology.class类。

enter image description here

我的第二个JAR文件ark-tweet-nlp-0.3.2.jar包含相同的包名称(edu.stanford.nlp.process)和相同的类名Morphology.class

enter image description here

在两个JARS中,在各自的Morphology类中都存在一个名为stem()的方法。但是,这些方法的构造函数是不同的。我想从我的第二个JAR文件中使用stem(String, String)方法,但由于import语句(import edu.stanford.nlp.process.Morphology;)没有指定要使用哪个JAR,因为它认为构建路径上的第一个JAR,我收到错误是我想要实现的那个。

我不想改变构建路径的顺序,因为它会抛弃我的其他方法调用。

如何指定要使用哪个JAR的Morphology类?是否有一个import语句指定JAR以及package.class?

编辑:如何组合我的两个JAR以便两个Morphology类合并,给我两个不同构造函数的方法?

6 个答案:

答案 0 :(得分:2)

默认ClassLoader只会加载其中一个广告,而忽略第二个广告,因此无法开箱即用。也许自定义ClassLoader可以提供帮助。

有关ClassLoader的详细信息,请从here开始。

祝你好运!

编辑:我们正在研究一些可怕的包装选择,这会导致这个Jar Hell的副作用。这个"Ark Twitter"库的作者认为发布包含第三方库(Stanford NLP库)的JAR工件是个好主意。这导致Ark Twitter与其使用的Stanford NLP库的特定版本之间不必要的紧密耦合。这是一种非常糟糕的做法,在任何情况下都应该不鼓励:这违反了关于传递依赖的整个想法。

编辑(续):一个可能(并且希望正在发挥作用)的解决方案是重建Ark Twitter JAR,使其包含上述库但只包含其自己的库代码(基本上只是cmu.arktweetnlp包)并希望您的项目所需的NLP版本与Ark Twitter一起使用。理想情况下,您应该向库的作者提交拉取请求,但与此同时,您可以通过解除乱码并重新震动现有的JAR文件。

编辑2 :再次查看JAR文件,我原先想到的情况要糟糕得多: ALL 依赖关系在已发布的JAR文件中重新打包。这实际上是发布库的最糟糕的解决方案。祝你好运。

答案 1 :(得分:2)

正如上面其他几位指出的那样,可以调整Java的类加载器机制来从某些地方加载类......但是这不是你想要的,相信我。

你遇到了一个已知问题。您应该考虑使用不同版本的ArkTweet,而不是担心如何告诉Java使用来自一个JAR而不是另一个JAR的类。

获取ArkTweet JAR from Maven Central。它不包含斯坦福大学的课程。

当你注意到人们在他们的JAR中打包第三方课程时,我建议他们指出这通常不是一个好主意,并鼓励他们不要这样做。如果一个项目提供了一个包含所有依赖项的可运行的fat-jar,那很好。但是,它不应该是他们提供的唯一JAR。还应提供没有任何第三方代码的普通JAR或JAR集。在极少数情况下,第三方代码被修改并且必须包含在内,它应该在提供者的包命名空间下完成,而不是在原始第三方的包名称下。

最后,要获得构建模块化Java应用程序和处理类加载器隔离的真正解决方案,请查看几个OSGi实现之一或项目Jigsaw

答案 2 :(得分:1)

不,没有。这是Java的一个弱点,无法简单地解决。您应该只使用其中一个库。在类路径中同时使用java将始终选择第一个。

此问题的名称为Jar hell

答案 3 :(得分:1)

构建路径中的顺序通常决定了类加载器搜索类的顺序。但是,一般情况下,您不希望在构建路径中重复同一个类 - 并且肯定看起来不像ark-tweet-nlp-0.3.2.jar中应该有一个edu.stanford包。

答案 4 :(得分:1)

我认为只需在当前CoreNLP的Morphology类中使用lemma(String word, String tag)方法即可解决您的问题:

String word = ...;
String tag = ...;
String lemma = morphology.lemma(word, tag);
WordTag wt = new WordTag(lemma, tag);

几年前修改课程时,您要查找的方法已被删除。感觉是,随着大多数斯坦福NLP代码转向使用CoreLabel s,返回WordTag的方法不太有用(尽管删除所有这些方法仍然是一项工作正在进行中)。

答案 5 :(得分:0)

当你加载一个类时,它被加载到给定的地址,然后该地址放在从类创建的对象的头中,这样(除其他外)可以找到类中的方法。

因此,如果以某种方式使用方法abc(String)从zip文件XYZ.zip加载ClassA,它将加载到地址12345.然后(使用类加载器技巧)加载另一个ClassA,方法为abc(String,String) ),从zip文件ZYX.zip,并加载到地址67890。

现在创建第一个ClassA的实例。在它的标题中,类地址为12345.如果你可以某种方式尝试在该类上调用方法abc(String,String),那么在12345的类中将找不到该方法。(实际上,你甚至不能尝试调用,因为验证者会阻止你,因为对它来说,这两个类是完全不同的,你试图使用另一个调用另一个类,就好像它们的名字完全不同。)