如何参考 Java 1.6 API,同时针对 Java 1.5 进行优雅降级?
我想使用 java.text.Normalizer< /a> Java 1.6 中的类来进行 Unicode 规范化,但我的代码必须能够在 Java 1.5 上运行。
我不介意在 1.5 上运行的代码是否不进行规范化,但我不希望它在运行时给出 NoClassDefFoundError
s 或 ClassNotFoundException
s。
实现这一目标的最佳方法是什么?
I would like to use the java.text.Normalizer class from Java 1.6 to do Unicode normalization, but my code has to be able to run on Java 1.5.
I don't mind if the code running on 1.5 doesn't do normalization, but I don't want it to give NoClassDefFoundError
s or ClassNotFoundException
s when it runs.
What's the best way to achieve this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
通常的方法是通过反射,即不直接引用相关类,而是以编程方式调用它。 如果相关代码不存在,这允许您优雅地捕获异常,并忽略它或尝试其他操作。 反射抛出
ClassNotFoundException
,这是一个很好的正常异常,而不是NoClassDefFoundError
,后者有点可怕。对于 java.text.Normalizer 来说,这应该非常简单,因为它只是几个静态方法,并且很容易通过反射调用。
The usual way of doing this is via reflection, i.e. don't refer directly to the class in question, but invoke it programmatically. This allows you to catch exceptions gracefully if the code in question doesn't exist, and either ignore it, or try something else. Reflection throws
ClassNotFoundException
, which is a nice normal exception, rather thanNoClassDefFoundError
, which is a bit scarier.In the case of
java.text.Normalizer
, this should be pretty easy, since it's just a couple of static methods, and easy to invoke via reflection.在您的客户端代码中:
In your client code:
如果你想避免反射,你实际上可以捕获这些错误。
这样,您可以使用 Java6 编译器针对闪亮的新类进行编译,并且它仍然可以在 Java5 上工作(如“不执行任何操作,但也不会崩溃”)。
您还可以结合这两种方法,并使用反射检查该类是否存在,以及是否继续以非反射方式调用它。 这就是安德鲁的解决方案正在做的事情。
如果您还需要在 Java5 上进行编译,那么您需要一直进行反射。
If you want to avoid reflection, you can actually catch those Errors.
This way, you can compile against the shiny new classes with a Java6 compiler, and it will still work (as in "not do anything, but also not crash") on Java5.
You can also combine the two approaches, and check if the class exists using reflection, and if it does continue to call it in a non-reflective way. This is what Andrew's solution is doing.
If you also need to compile on Java5, then you need to go reflection all the way.
我也有同样的需求,因为我们的代码需要在 Java 1.2 以来的所有 Java 版本上运行,但有些代码需要利用较新的 API(如果可用)。
在使用反射获取 Method 对象并动态调用它们的各种排列之后,一般来说,我选择了最好的包装器样式方法(尽管在某些情况下,仅将反射的 Method 存储为静态并调用它更好 - 这取决于) 。
以下是一个示例“系统实用程序”类,它在运行早期版本时公开了 Java 5 的某些较新的 API - 相同的原则也适用于早期 JVM 中的 Java 6。 此示例使用 Singleton,但如果底层 API 需要,可以轻松实例化多个对象。
有两个类:
如果运行时 JVM 是 Java 5 或更高版本,则使用后者。 否则,将使用 SysUtil 中的默认实现中兼容的后备方法,该实现仅使用 Java 4 或更早的 API。 每个类都使用特定版本的编译器进行编译,因此 Java 4 类中不会意外使用 Java 5+ API:
SysUtil(使用 Java 4 编译器编译)
SysUtil_J5(使用 Java 5 编译器编译)
I have had this same need, since we have code that needs to run on all versions of Java from Java 1.2, but some code needs to take advantage of newer API's if they are available.
After various permutations using reflection to obtain Method objects and invoking them dynamically, I have settled on a wrapper style approach as best, in general (although under some circumstances, just storing the reflected Method as a static and invoking it is better - it depends).
Following is an example "System Utility" class which exposes certain newer API's for Java 5 when running an earlier version - the same principles hold for Java 6 in earlier JVMs. This example uses a Singleton, but could easily instantiate multiple objects if the underlying API needed that.
There are two classes:
The latter is the one used if the run-time JVM is Java 5 or later. Otherwise fallback methods which are compatible in contract are used from the default implementation in SysUtil which utilizes only Java 4 or earlier APIs. Each class is compiled with the specific version's compiler, so that there is no accidental usage of a Java 5+ API in the Java 4 class:
SysUtil (compiled with the Java 4 compiler)
SysUtil_J5 (compiled with the Java 5 compiler)
检查/使用/修改类 Phramer 项目中的 info.olteanu.utils.TextNormalizer (http://sourceforge.net/projects/ Phramer/ , www.phramer.org ) - 代码已获得 BSD 许可。
该代码可以在 Java 5 中编译并在 Java 5 或 Java 6(或未来的 Java 版本)中运行。 此外,它可以在 Java 6 中编译并在 Java 5 中运行(如果使用正确的“-target”进行编译,以实现字节码兼容性)或 Java 6 或任何其他未来版本。
恕我直言,这完全解决了您的问题 - 您可以在任何 Java 5+ 平台上自由编译,并且您能够在任何 Java 5+ 平台上获得所需的功能(标准化) (*)
(*) SUN Java 5 标准化解决方案很可能不会出现在所有 Java 5 实现中,因此在最坏的情况下,当您调用 getNormalizationStringFilter() 方法时,您最终会得到 ClassNotFoundException。
Check/use/modify class info.olteanu.utils.TextNormalizer in Phramer project (http://sourceforge.net/projects/phramer/ , www.phramer.org ) - the code is BSD licensed.
That code can be compiled in Java 5 and runs both in Java 5 or Java 6 (or future Java versions). Also, it can be compiled in Java 6 and be run in Java 5 (if it was compiled with the proper "-target", for bytecode compatibility) or Java 6 or any other future version.
IMHO this fully solves your problem - you are free to compile on any Java 5+ platform, and you are able to get the functionality desired (normalization) on any Java 5+ platform (*)
(*) The SUN Java 5 solution for normalization will most likely not be present on all Java 5 implementations, so in the worst case scenario you will end up getting a ClassNotFoundException when you call getNormalizationStringFilter() method.
这是老问题,但仍然是现实的。 我发现了一些答案中没有提到的可能性。
通常建议使用反射,如此处其他一些答案所示。 但如果您不想让代码变得混乱,可以使用 icu4j 库。 它包含
com.ibm.icu.text.Normalizer
类以及normalize()
方法,该方法执行与 java.text.Normalizer/sun.text.Normalizer 相同的工作。 Icu 库有(应该有)自己的 Normalizer 实现,因此您可以与库共享您的项目,并且应该独立于 java。缺点是 icu 库相当大。
如果您使用 Normalizer 类只是为了从字符串中删除重音符号/变音符号,还有另一种方法。 您可以使用包含
StringUtils
的 Apache commons lang 库(版本 3)使用方法stripAccents()
:Lang3 库可能使用反射根据 java 版本调用适当的 Normalizer。 所以优点是你的代码中不会出现反射混乱。
This is old question, but still actual. I found out some possibilities that are not mentioned in answers.
Usually it is recommended to use reflection as is shown in some other answers here. But if you don't want to put mess in your code, you can use icu4j library. It contains
com.ibm.icu.text.Normalizer
class withnormalize()
method that perform the same job as java.text.Normalizer/sun.text.Normalizer. Icu library has (should have) own implementation of Normalizer so you can share your project with library and that should be java-independent.Disadvantage is that the icu library is quite big.
If you using Normalizer class just for removing accents/diacritics from Strings, there's also another way. You can use Apache commons lang library (ver. 3) that contains
StringUtils
with methodstripAccents()
:Lang3 library probably use reflection to invoke appropriate Normalizer according to java version. So advantage is that you don't have reflection mess in your code.