【问题标题】:Migration Issue to Java 11 from legacy code从遗留代码迁移到 Java 11 的问题
【发布时间】:2019-01-22 10:54:38
【问题描述】:

我们正在将旧代码迁移到 Java 11,实际上已经很旧了。我在编译其中一个类时遇到了问题。示例代码为:

package XXXX;

import java.lang.ref.*;
import sun.security.action.*;
import java.security.*;
import java.io.*;

class Converters
{
    private static Object lock;
    private static String converterPackageName;
    private static String defaultEncoding;
    public static final int BYTE_TO_CHAR = 0;
    public static final int CHAR_TO_BYTE = 1;
    private static final String[] converterPrefix;
    private static SoftReference[] classCache;
    static /* synthetic */ Class class$sun$io$Converters;

    private static String getConverterPackageName() {
        final String converterPackageName = Converters.converterPackageName;
        if (converterPackageName != null) {
            return converterPackageName;
        }
        String converterPackageName2 = AccessController.doPrivileged((PrivilegedAction<String>)new GetPropertyAction("file.encoding.pkg"));
        if (converterPackageName2 != null) {
            Converters.converterPackageName = converterPackageName2;
        }
        else {
            converterPackageName2 = "sun.io";
        }
        return converterPackageName2;
    }

    private static Class getConverterClass(final int n, final String s) throws UnsupportedEncodingException {
        String aliasName = null;
        if (!s.equals("ISO8859_1")) {
            if (s.equals("8859_1")) {
                aliasName = "ISO8859_1";
            }
            else if (s.equals("ISO8859-1")) {
                aliasName = "ISO8859_1";
            }
            else if (s.equals("646")) {
                aliasName = "ASCII";
            }
            else {
                aliasName = CharacterEncoding.aliasName(s);
            }
        }
        if (aliasName == null) {
            aliasName = s;
        }
        try {
            return Class.forName(getConverterPackageName() + "." + Converters.converterPrefix[n] + aliasName);
        }
        catch (ClassNotFoundException ex) {
            throw new UnsupportedEncodingException(aliasName);
        }
    }

    private static Object newConverter(final String s, final Class clazz) throws UnsupportedEncodingException {
        try {
            return clazz.newInstance();
        }
        catch (InstantiationException ex) {
            throw new UnsupportedEncodingException(s);
        }
        catch (IllegalAccessException ex2) {
            throw new UnsupportedEncodingException(s);
        }
    }

    static Object newConverter(final int n, final String s) throws UnsupportedEncodingException {
        final Class converterClass;
        synchronized (Converters.lock) {
            converterClass = getConverterClass(n, s);
        }
        return newConverter(s, converterClass);
    }

    private static Class getDefaultConverterClass(final int n) {
        boolean b = false;
        final SoftReference softReference = Converters.classCache[n];
        if (softReference != null) {
            final Class clazz = softReference.get();
            if (clazz != null) {
                return clazz;
            }
            Converters.classCache[n] = null;
        }
        String defaultEncoding = Converters.defaultEncoding;
        if (Converters.defaultEncoding != null) {
            b = true;
        }
        else {
            defaultEncoding = AccessController.doPrivileged((PrivilegedAction<String>)new GetPropertyAction("file.encoding"));
            if (defaultEncoding != null) {
                Converters.defaultEncoding = defaultEncoding;
                b = true;
            }
            else {
                defaultEncoding = "ISO8859_1";
            }
        }
        Class clazz2;
        try {
            clazz2 = getConverterClass(n, defaultEncoding);
            if (b) {
                Converters.classCache[n] = new SoftReference(clazz2);
            }
        }
        catch (UnsupportedEncodingException ex) {
            try {
                clazz2 = getConverterClass(n, "ISO8859_1");
            }
            catch (UnsupportedEncodingException ex2) {
                throw new InternalError("Cannot find default " + Converters.converterPrefix[n] + " converter class");
            }
        }
        return clazz2;
    }

    static Object newDefaultConverter(final int n) {
        final Class defaultConverterClass;
        synchronized (Converters.lock) {
            defaultConverterClass = getDefaultConverterClass(n);
        }
        try {
            return newConverter("", defaultConverterClass);
        }
        catch (UnsupportedEncodingException ex) {
            throw new InternalError("Cannot instantiate default converter class " + defaultConverterClass.getName());
        }
    }

    static /* synthetic */ Class class$(final String s) {
        try {
            return Class.forName(s);
        }
        catch (ClassNotFoundException ex) {
            throw new NoClassDefFoundError(ex.getMessage());
        }
    }

    static {
        Converters.lock = ((Converters.class$sun$io$Converters == null) ? (Converters.class$sun$io$Converters = class$("sun.io.Converters")) : Converters.class$sun$io$Converters);
        Converters.converterPackageName = null;
        Converters.defaultEncoding = null;
        converterPrefix = new String[] { "ByteToChar", "CharToByte" };
        Converters.classCache = new SoftReference[2];
    }
}

使用javac Converter.java 编译时,我收到以下错误:

import sun.security.action.*;
                   ^
  (package sun.security.action is declared in module java.base, which does not export it to the unnamed module)
Converters.java:47: error: cannot find symbol
                aliasName = CharacterEncoding.aliasName(s);
                            ^
  symbol:   variable CharacterEncoding
  location: class Converters
Converters.java:85: error: incompatible types: Object cannot be converted to Class
            final Class clazz = softReference.get();
                                                 ^
Note: Converters.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Converters.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
3 errors

我尝试使用--add--export java.base/sun.security=All-UNNAMED 导出它,它仍然抛出错误。

有什么帮助吗?还想知道有没有其他方法可以用新的旧代码删除这个旧代码。

【问题讨论】:

  • 这不是您的遗留代码,这是在 JDK 类上运行反编译器的结果。您需要将此代码编译为系统的一部分,这非常奇怪。
  • sun.* 包是 JVM 内部的,从未打算供实现类使用。如果你以前没有被它咬过,那你真是太幸运了。
  • 哦,我明白了,它被捆绑在一个罐子里。有没有在新库中使用它的替代方法
  • 当然,还有其他选择。不要使用该代码。一旦我们知道您真正想要做什么,我们就可以告诉您如何去做。 Java 从 1.1 版本开始就有易于使用的字符集转换方法。
  • CharacterEncoding 位于 sun.io,自 Java 1.6 起已弃用(现已删除)。请改用java.nio.charset

标签: java java-9 java-11


【解决方案1】:

从 Java 9 开始,大部分 JDK 的内部 API are inaccessible at compile time(在未来,它们也将在运行时无法访问)。 sun.security.action 是一个内部包,所以你应该避免使用它。在您的情况下,您可以简单地删除 new GetPropertyAction("file.encoding.pkg") 并将其替换为 lambda:

AccessController.doPrivileged((PrivilegedAction<Object>) () -> System.getProperty("prop"));

【讨论】:

  • 感谢您的建议,非常感谢。但我期待更换旧的自制罐子。有没有更好的方法来替换它。
  • 最终 ByteToCharRoman8 转换器 = new ByteToCharRoman8();最终字节[] ba = 新字节[] { b };最终字符 [] ca = 新字符 [1];转换器.convert(ba, 0, 1, ca, 0, 1);
  • ByteToCharRoman8 是一个相当古老的 java 库,很久以前就被某个团队捆绑在一个自制的 jar 中。
【解决方案2】:

正如所指出的,这些是不应直接使用的内部类。如果重构超出范围,您应该使用--add-export,这应该可以工作!

您的--add-export 参数是错误的。您需要使用正确的包来导出(在您的情况下为sun.security.action)和模块的名称(如果您不使用模块,则ALL-UNNAMED,全部使用大写字母!)。

所以这应该是--add-exports java.base/sun.security.action=ALL-UNNAMED

来自 javac 的文档:

--add-exports module/package=other-module(,other-module)* 指定一个包被视为从其定义模块导出到 附加模块或所有未命名的模块时的值 other-module 是 ALL-UNNAMED。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-07
    • 2020-02-05
    • 2021-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多