在交付单个 jar 并使用反射时,如何避免需要在命令行上指定完全限定的类名?

发布于 2024-12-26 16:39:05 字数 2915 浏览 1 评论 0原文

我有一个代码库,我想生成几个可交付的 jar 文件,每个文件都从命令行运行并访问代码库的某些功能。运行时,一些命令行参数是 jar 中的其他类,然后通过反射创建它们。它工作得很好,但我必须指定类的很长的完全限定路径,即使这些类位于 jar 文件中。

我正在使用 ant 编译然后 jar 一系列目录。从最小的示例 build.xml 文件:

<property name="build" location="build"/>
<property name="jars" location="${build}/jars"/>
<property name="classes" location="${build}/classes"/>
<property name="src" location="src/dom/place/proj"/>

<target name="utility">
 <javac 
    includeantruntime="false" 
    srcdir="${src}/utility" destdir="${classes}" 
    classpathref="classpath" />
 <jar 
    destfile="${jars}/utility.jar" 
    basedir="${classes}" 
    includes="**/utility/**" />
</target>

<target name="tokenizers" depends="utility">
 <javac 
    includeantruntime="false" 
    srcdir="${src}/tokenizers" 
    destdir="${classes}" 
    classpathref="classpath" />
 <jar 
    destfile="${jars}/tokenizers.jar" 
    basedir="${classes}" 
    includes="**/tokenizers/**" />
</target>

稍后,我创建一个包含所有需要的类的单个 jar 文件,并将运行命令,例如:

<target name="tokenize-file-jar">
 <jar destfile="${dist}/TokenizeFile.jar">
  <zipgroupfileset dir="${jars}">
    <include name="utility.jar"/>
    <include name="tokenizers.jar"/>
  </zipgroupfileset>
  <manifest>
    <attribute name="Main-Class" value="dom.place.proj.tokenizers.TokenizeFile"/>
  </manifest>     
 </jar>    
</target>

这一切都有效,并且在 jar 文件中查找,所有类都在那里。

prompt > unzip -l TokenizeFile.jar 
Archive:  TokenizeFile.jar
Length     Date   Time    Name
--------    ----   ----    ----
        0  01-11-12 11:07   META-INF/
      286  01-11-12 11:07   META-INF/MANIFEST.MF
        0  01-11-12 10:16   dom/
        0  01-11-12 10:16   dom/place/
        0  01-11-12 10:16   dom/place/proj/
        0  01-11-12 10:16   dom/place/proj/tokenizers/
     1737  01-11-12 11:07   dom/place/proj/tokenizers/FileTokenizer.class
     1411  01-11-12 11:07   dom/place/proj/tokenizers/PorterTokenizer.class
     1754  01-11-12 11:07   dom/place/proj/tokenizers/TokenizeFile.class
      992  01-11-12 11:07   dom/place/proj/tokenizers/Tokenizer.class
        0  01-11-12 10:16   dom/place/proj/utility/
     1106  01-11-12 11:07   dom/place/proj/utility/BoundedExecutor.class
     3128  01-11-12 11:07   dom/place/proj/utility/Converter.class
     1107  01-11-12 11:07   dom/place/proj/utility/ExceptionHandler.class

现在,要运行代码,我执行以下操作:

java -jar TokenizeFile.jar test.txt dom.place.proj.tokenizers.FileTokenizer dom.place.proj.tokenizers.PorterTokenizer

它可以工作。耶!但我希望我的客户不必在命令行上指定每个类的完全限定名称 - 这是一个小示例,可能有很多项目。我可以在代码或构建过程中更改什么来允许这样做:

java -jar TokenizeFile.jar test.txt FileTokenizer PorterTokenizer

感谢您的帮助。我正在从 C++/make 过渡,到目前为止非常喜欢 ant 和 Java。

I have a codebase that I want to produce several deliverable jar files, each of which is to be run from the command line and which accesses some functionality of the codebase. When run, some of the command-line parameters are other classes within the jar that are then created by reflection. It works, nicely, but I have to specify the very long fully qualified path to the class, even though the classes are within the jar file.

I am using ant to compile and then jar a series of directories. From a minimal sample build.xml file:

<property name="build" location="build"/>
<property name="jars" location="${build}/jars"/>
<property name="classes" location="${build}/classes"/>
<property name="src" location="src/dom/place/proj"/>

<target name="utility">
 <javac 
    includeantruntime="false" 
    srcdir="${src}/utility" destdir="${classes}" 
    classpathref="classpath" />
 <jar 
    destfile="${jars}/utility.jar" 
    basedir="${classes}" 
    includes="**/utility/**" />
</target>

<target name="tokenizers" depends="utility">
 <javac 
    includeantruntime="false" 
    srcdir="${src}/tokenizers" 
    destdir="${classes}" 
    classpathref="classpath" />
 <jar 
    destfile="${jars}/tokenizers.jar" 
    basedir="${classes}" 
    includes="**/tokenizers/**" />
</target>

Later, I am creating a single jar file that includes all needed classes and will run a command, for example:

<target name="tokenize-file-jar">
 <jar destfile="${dist}/TokenizeFile.jar">
  <zipgroupfileset dir="${jars}">
    <include name="utility.jar"/>
    <include name="tokenizers.jar"/>
  </zipgroupfileset>
  <manifest>
    <attribute name="Main-Class" value="dom.place.proj.tokenizers.TokenizeFile"/>
  </manifest>     
 </jar>    
</target>

This all works, and looking in the jar file, all the classes are there.

prompt > unzip -l TokenizeFile.jar 
Archive:  TokenizeFile.jar
Length     Date   Time    Name
--------    ----   ----    ----
        0  01-11-12 11:07   META-INF/
      286  01-11-12 11:07   META-INF/MANIFEST.MF
        0  01-11-12 10:16   dom/
        0  01-11-12 10:16   dom/place/
        0  01-11-12 10:16   dom/place/proj/
        0  01-11-12 10:16   dom/place/proj/tokenizers/
     1737  01-11-12 11:07   dom/place/proj/tokenizers/FileTokenizer.class
     1411  01-11-12 11:07   dom/place/proj/tokenizers/PorterTokenizer.class
     1754  01-11-12 11:07   dom/place/proj/tokenizers/TokenizeFile.class
      992  01-11-12 11:07   dom/place/proj/tokenizers/Tokenizer.class
        0  01-11-12 10:16   dom/place/proj/utility/
     1106  01-11-12 11:07   dom/place/proj/utility/BoundedExecutor.class
     3128  01-11-12 11:07   dom/place/proj/utility/Converter.class
     1107  01-11-12 11:07   dom/place/proj/utility/ExceptionHandler.class

Now, to run the code, I do:

java -jar TokenizeFile.jar test.txt dom.place.proj.tokenizers.FileTokenizer dom.place.proj.tokenizers.PorterTokenizer

and it works. Yay! But I would prefer my client not have to specify the fully qualified name for each class on the command line - this is a small example, and there may be many items. What can I change, in my code or in my build process, to allow this instead:

java -jar TokenizeFile.jar test.txt FileTokenizer PorterTokenizer

Thanks for your help. I am transitioning from C++/make and like ant and Java very much so far.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

眼波传意 2025-01-02 16:39:05

简短而简单的答案是这是不可能的;类名只有在其包的情况下才明确。

让调用者变得更简单的一个选择是让您的应用程序在它们提供的每个类参数前面添加 "dom.place.proj.tokenizers." - 这样您的较短的首选示例的行为将与第一个示例相同。

然而,越简单的功能就越弱。用户将不再可能定义自己的自定义类并将其传递进去,因为包不匹配。 (在某种程度上,如果类名不包含句点(.),您可以通过仅在前面添加默认包来解决此问题,但是添加的特殊情况越多,这将越难理解...)


您提到您正在过渡到 Java。归根结底,当类出现在这种情况下时,我期望会通过其完整的包前缀名称指定类,因此缩写版本可能会让使用过的人感到更加困惑到爪哇。

因此,我的建议是保持现状,基本上,更加习惯命令行的第一个版本。即使您要解决这种特殊情况下的问题,还有许多其他第一方和第三方 Java 应用程序和工具需要在命令行上指定类 - 并且它们都需要完全限定的类名也。

如果这看起来不太像是一个答案,我深表歉意,但我相信这是在这种情况下最好的行动方案。

The short and simple answer is that this isn't possible; class names are only unambiguous given their package as well.

One option to make things simpler to callers is have your application prepend "dom.place.proj.tokenizers." to each class argument they provide - so your shorter, preferred example would behave identically to the first one.

However, with great simplicity comes diminished power; it would no longer be possible for a user to define their own custom class and pass it in, as the packages wouldn't match. (To some extent you could work around this by only prepending the default package if the class name doesn't contain a period (.), but the more special cases you add the harder this will be to understand...)


You mention that you're transitioning to Java. At the end of the day, I would expect to have classes specified by their full package-prefixed name when they appear in situations like this, and so the abbreviated version would likely be more confusing to someone who's used to Java.

My recommendation therefore is to leave things as they are now, and, basically, become more accustomed to the first version of the command line. Even if you were to solve the problem in this particular case, there are many other first-party and third-party Java apps and tools that require classes to be specified on the command-line - and they all require the fully-qualified class name too.

Apologies if this doesn't seem much like an answer, but I believe it is the best course of action in this situation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文