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 条评论
登录 后参与评论

相关文章

来自专栏张善友的专栏

使用Hystrix提高系统可用性

今天稍微复杂点的互联网应用,服务端基本都是分布式的,大量的服务支撑起整个系统,服务之间也难免有大量的依赖关系,依赖都是通过网络连接起来。 ? (图片来源:htt...

23150
来自专栏Linyb极客之路

使用lazyInit缩短Spring Boot启动时间

Spring Boot可以进行有助于相关针对项目的设置,包括最常见的默认设置和随时可用的配置,这无疑是很棒的,因为它节省了宝贵的时间 然而,对于框架的新手来说,...

1.6K70
来自专栏菩提树下的杨过

redis 学习笔记(4)-HA高可用方案Sentinel配置

上一节中介绍了master-slave模式,在最小配置:master、slave各一个节点的情况下,不管是master还是slave down掉一个,“完整的”...

23970
来自专栏向治洪

android studio比较长用的几款插件

不懂安装studio插件,看参考博文:android stuido插件安装:http://blog.csdn.net/liang5630/article/de...

20780
来自专栏散尽浮华

Redis+Keepalived高可用环境部署记录

26760
来自专栏Urahara Blog

域渗透-信息收集基础

89050
来自专栏区块链入门

第4课 如何在UBUNTU虚拟机上编译EOS完成环境搭建?

【本文目标】 通过本文实践,能在WINDOWS操作系统搭建UBUNTU 18.04 LTS环境,并在此环境编译成功EOS v1.0.5正式发布版本。 【前置...

36450
来自专栏草根专栏

常见形式 Web API 的简单分类总结

请求--响应类的API的典型做法是,通过基于HTTP的Web服务器暴露一个/套接口。API定义一些端点,客户端发送数据的请求到这些端点,Web服务器处理这些请求...

19530
来自专栏FreeBuf

Metasploitable2使用指南

Metasploitable 2 Metasploitable2 虚拟系统是一个特别制作的ubuntu操作系统,本身设计作为安全工具测试和演示常见漏洞攻击。版...

66490
来自专栏杂烩

SSM项目搭建之MyBatis 原

    MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了goog...

9120

扫码关注云+社区

领取腾讯云代金券