专栏首页光变Javac命令使用ct.sym文件约束可使用的类

Javac命令使用ct.sym文件约束可使用的类

在JDK6,升级为JDK7或者JDK8的过程中会遇到一些奇怪的问题,简单的介绍一下经典的ClassNotFoundsun.nio.*com.sun.image.codec.jpeg.*等。

背景简介

很多项目使用在JDK6升级到JDK7或者JDK8的过程中,会遇到一些问题。 本文主要介绍一下,在升级过程中,JDK的部分类在Android Studio、Eclipse(以下概称IDE,不包括神器NetBeans)的编译过程中没有提示。 但是使用Maven、Ant、Gradle(这三个工具在下文中概称为打包工具)打包的过程中,会出现错误‘ClassNotFound’‘程序包sun.net.sdp不存在’。 例如:

  • com.sun.image.codec.jpeg.JPEGCodec
  • com.sun.image.codec.jpeg.JPEGEncodeParam
  • jdk.internal.org.objectweb.asm.commons.AdviceAdapter
  • sun.net.sdp.SdpSupport

示例

JDK6可以编译通过、JDK7和JDK8在IDE中可以编译通过,但是使用打包工具,则编译不通过。

import com.sun.image.codec.jpeg.JPEGCodec;
public class TestCtSymJdk6Pass {
    private JPEGCodec jpegCodec;
}

编译尝试

jdk1.6/bin/javac TestCtSymJdk6Pass.java.java

通过,但是会有两个警告。

TestCtSymJdk6Pass.java:1: 警告:com.sun.image.codec.jpeg.JPEGCodec 是 Sun 的专用 API,可能会在未来版本中删除
import com.sun.image.codec.jpeg.JPEGCodec;
                               ^
TestCtSymJdk6Pass.java:3: 警告:com.sun.image.codec.jpeg.JPEGCodec 是 Sun 的专用 API,可能会在未来版本中删除
    private JPEGCodec jpegCodec;
            ^
2 警告

jdk1.7/bin/javac TestCtSymJdk6Pass.java jdk1.8/bin/javac TestCtSymJdk6Pass.java

不通过,两个错误

TestCtSymJdk6Pass.java:1: 错误: 程序包com.sun.image.codec.jpeg不存在
import com.sun.image.codec.jpeg.JPEGCodec;
                               ^
TestCtSymJdk6Pass.java:3: 错误: 找不到符号
    private JPEGCodec jpegCodec;
            ^
  符号:   类 JPEGCodec
  位置: 类 TestCtSymJdk6
2 个错误

JDK6-8都编译不通过

import com.sun.image.codec.jpeg.JPEGCodec;
import sun.net.sdp.SdpSupport;
public class TestCtSymJdk6NotPass {
    private JPEGCodec jpegCodec;
    private SdpSupport sdpSupport;
}

JDK6报错

TestCtSymJdk6NotPass.java:1: 警告:com.sun.image.codec.jpeg.JPEGCodec 是 Sun 的专用 API,可能会在未来版本中删除
import com.sun.image.codec.jpeg.JPEGCodec;
                               ^
TestCtSymJdk6NotPass.java:2: 软件包 sun.net.sdp 不存在
import sun.net.sdp.SdpSupport;
                  ^
TestCtSymJdk6NotPass.java:4: 警告:com.sun.image.codec.jpeg.JPEGCodec 是 Sun 的专用 API,可能会在未来版本中删除
    private JPEGCodec jpegCodec;
            ^
TestCtSymJdk6NotPass.java:5: 找不到符号
符号: 类 SdpSupport
位置: 类 TestCtSymJdk6NotPass
    private SdpSupport sdpSupport;
            ^
2 错误
2 警告

添加编译参数:忽略链接文件

jdk1.6/bin/javac -XDignore.symbol.file TestCtSymJdk6NotPass.java jdk1.7/bin/javac -XDignore.symbol.file TestCtSymJdk6Pass.java jdk1.8/bin/javac -XDignore.symbol.file TestCtSymJdk6Pass.java

以上三条命令都可以正常执行。

原因

在JDK6以及以后的版本,JDK在目录下新增了一个链接文件${JDK_HOME}/lib/ct.sym文件。 在使用javac命令进行编译代码时,默认使用该文件进行编译时class类的检查和链接,而不是使用rt.jar

该文件保存了JDK建议使用的类描述信息。com.sun.*包和sun.*包,以及新的jdk.*都不是Open的API,是JDK内部的私有类,这些类的接口可能在之后的版本变动,也不保证平台移植性。

事实上,JDK提供的Public API,仅有三个包:java.*javax.*org.*。它们是官方支持的公共接口(Official、Supported、Public )。

ct.sym文件是一个zip压缩包,它里面包含了部分rt.jar中的类。

ct.sym中的类文件都是简单的空函数,不包含函数体,所以非常小。

ct.sym中如果没有该类,则会出现ClassNotFound的错误。 比如JDK6中的sun.net.sdp.SdpSupport类。在ct.sym中就没有sun.net.sdp包。

比如JDK7中的com.sun.image.codec.jpeg.JPEGCodec类。

解决方案

方案-1 【建议】

使用JDK开放的接口实现这部分功能。

方案-2 【临时方案】

在编译的时候加入参数-XDignore.symbol.file.

Maven

<build>
  <plugins>
    <plugin>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.6.0</version>
      <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <encoding>UTF-8</encoding>
        <compilerArgs>
          <arg>-XDignore.symbol.file</arg>
        </compilerArgs>
        <fork>true</fork>
      </configuration>
    </plugin>
  </plugins>
</build>

Ant

<target name="compile">
  <javac
    srcdir="src"
    destdir="bin"
    encoding="UTF-8"
    source="1.8"
    target="1.8">
    <compilerarg value="-XDignore.symbol.file"/>  
    <classpath refid="classpath" />
  </javac>
</target>

Gradle

compileJava.options.compilerArgs = [ '-XDignore.symbol.file=true' ]

方案-3 【不建议】

非常粗暴!直接删除ct.sym文件。

PS

PS

神器-NetBeans在IDE中就会提示该错误。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 『C』ubuntu命令大合集

    查看软件xxx安装内容dpkg -L xxx查找软件库中的软件apt-cache search 正则… 查看软件xxx安装内容 dpkg -L xxx 查找软...

    白凡
  • Gradle Unable to blame file

    白凡
  • SpringMVC 异步提交表单数据

    白凡
  • 北森云计算 CEO&联合创始人纪伟国:SaaS第三代的盛世危言

    T客汇官网:tikehui 撰文 |卿云 中美SaaS峰会|2017年中国SaaS产业峰会于2017年5月10日在北京新云南皇冠假日酒店举行,峰会主题:探索·共...

    人称T客
  • mybatis文件映射之利用延迟加载解决collection分布查询(六)

    DEBUG 01-20 19:35:58,093 ==> Preparing: select id,dept_name from tbl_department ...

    绝命生
  • MEDUZA:一款针对iOS应用程序的通用SSL解绑工具

    MEDUZA是一款针对iOS应用程序的通用SSL解绑工具,该工具基于Frida开发,可以当作SSLKillSwitch工具的替代品。本来我是想自己开发自己用的,...

    FB客服
  • Redis的Multi的内幕真相

    由于本人太忙不想去阅读Redis Server的源代码(其实是懒),就通过TCPDump来分析吧。

    sunsky
  • 对象存储 COS 和云函数 SCF 结合的轻应用及其技术原理 | 在线分享第五期

    7 月 17 日(周五)19:00,Tencent Serverless Hours 第五期线上分享会即将举办,届时将有腾讯云存储产品经理林楠、腾讯云存储前端...

    腾讯云serverless团队
  • 区块链旅游时代打造的健康生态自治社区

    目前,区块链旅游的应用观念已经从引导期逐步步入稳定期,并因区块链“技术革命”力量的影响而成为新一代引领旅游行业的发展的先驱。但是目前市场仍就市场乱象、以及不文明...

    区块链先锋
  • 腾讯反病毒实验室为你揭秘Xshell软件后门技术!

    背景: 最近,XShell远程终端工具发现被加入了恶意代码,目前官方就此事也做出了回应,要求使用者尽快下载最新版本。腾讯安全反病毒实验室就此跟进分析,对此次带...

    小小科

扫码关注云+社区

领取腾讯云代金券