搭建Java源码阅读环境,有两种类型,一种是调试 Java API 代码,另一种是深入 Java 底层编译 C++ 代码。本文主要还停留在 API 层面,搭建的是阅读 Java API 代码的环境。
本文使用的 JDK 是 1.8.0_131。
创建项目和首次编译:
关于步骤,网上很多可以找到的,我这里就提供两个链接:
创建 Java 项目源码阅读环境 here
创建 Maven 项目源码阅读环境 here
主要流程:
- 创建空项目(Java 或者 Maven 项目)
- 拷贝安装jdk的目录中拷贝 src.zip 解压到新建的空项目中
- Build 项目
问题一:源值1.5已过时
Error:(131, 21) java: -source 1.5 中不支持 diamond 运算符 (请使用 -source 7 或更高版本以启用 diamond 运算符),如下图所示:
原因解析:
Java 版本不对。
解决方法:
1.首先,修改 Settings 中 Java Compiler 配置:
2.然后,修改项目 Modules 模块中的 Language Level 配置:
关于修改 Language Leve 后的警告:
解决建议:
在 pom.xml 中增加这段配置:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<encoding>UTF-8</encoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
问题一解决参考博客:
git下载的项目报错:Warning:java: 源值1.5已过时, 将在未来所有发行版中删除;找不到或无法加载主类...
maven 指定java版本1.8
问题二:UNIXToolkit和FontConfigManager 找不到
Error:(27, 15) java: 找不到符号 符号: 类 UNIXToolkit 位置: 程序包 sun.awt
Error:(33, 16) java: 找不到符号 符号: 类 FontConfigManager 位置: 程序包 sun.font
因为Windows环境下缺少了两个文件导致的,我们需要自己去OpenJDK网站下载 OpenJDK。
给你们 2 个链接:
-
OpenJdk sun.awt,找到 UNIXToolkit 并拷贝下来。
-
OpenJdk sun.font,找到 FontConfigManager 并拷贝下来。
下载地址由 JDK8源码阅读-WINDOWS下环境搭建 提供!
问题三:com.sun.tools.javac.api不存在
Error:(40, 31) java: 程序包com.sun.tools.javac.api不存在。
1.拷贝 JDK安装目录/lib/tools.jar 到 Maven项目根目录/lib/tools.jar
2.打开 Project Structure -> Libraries 新增本地依赖 tools.jar
引入Junit源码调试
我不太想在 src/main/java 添加太多的类,所以我选择引入单元测试,你们可以选择引入 Junit4,这样比较简单
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
我最近了解了 Junit5 和 AssertJ 想要尝试一下,所以我用的是
<dependencies>
<!-- JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>4.12.1</version>
<scope>test</scope>
</dependency>
<!--AssertJ 流式断言-->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.17.0</version>
<scope>test</scope>
</dependency>
</dependencies>
然后创建一个测试用例,我这里用的 Junit5 + AssertJ 的测试用例哦,Junit4 使用时会编译错误。
import org.junit.Test;
import org.junit.jupiter.api.DisplayName;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class FirstTest {
@Test
@DisplayName("首次测试")
public void first_test() {
List<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
assertThat(list).hasSize(3)
.contains("张三");
}
}
关于引入 Junit5 时如何配置 pom.xml
官网:Junit5 user-guide
GitHub:junit5-jupiter-starter-maven/pom.xml
如果你访问不了 GitHub:解决mvn test运行Junit5测试用例时检测不到测试类的问题 ,有截图。
问题四:Debug总是进入反编译class
既然是源码阅读,我们肯定希望代码能够进入我们的类中,而不是进入反编译的 class 类。
4.1 创建移除 rt.jar 的 Platform SDK
首先,打开 Project Structure,在 SDKs 点击 +
选择 JDK8 安装目录,创建一个名为 1.8-without-rt 的 SDK, 并从 ClassPath 中移除 rt.jar。
项目之间是共享 SDK 的,因此建议保留原来的 SDK 1.8,然后创建一个新的 1.8-without-rt 来做调试之用
4.2 修改 Project SDK
在 Project Structure 中,切换到 Project Settings 下的 Project 栏,选择 Project SDK 为刚才新建的 1.8-without-rt
4.3 引入 lib/rt.jar 为本地依赖
引入 lib/rt.jar 是为了解决切换到 1.8-without-rt 导致找不到 sun.misc.Unsafe 等类的问题。
现在,我们的源码项目的代码变成首选了。
问题五:程序包sun.reflect.misc不存在
Error:(72,24) java: 程序包sun.reflect.misc不存在
Error:(152,24) java: 程序包javax.crypto不存在
Error:(40,31) java: 程序包com.sun.tools.javac.api不存在
【官方解释】:javac uses a special symbol table that does not include all Sun-proprietary classes. When javac is compiling code it doesn't link against rt.jar by default. Instead it uses special symbol file lib/ct.sym with class stubs.大意是:javac在编译时,并不引用 rt.jar,用的是一个特别的symbol table(lib/ct.sym),这个symbol table不包含所有的sun包的类。
【具体原因】:J2SE中的类大致可以划分为以下的各个包:java.,javax.,org.,sun.;除了“sun”包,其它各个包都是Java平台的标准实现,并且今后也将被继续支持。一般说来,“sun”之类的包并不包含在Java平台的标准中,它与操作系统相关,在不同的操作系统(如Solaris,Windows,Linux,Mac等等)中的实现也各不相同,并且可能随着J2SE版本不定期变化。因此,直接调用“sun”包的程序代码并不是100%的Java实现。也就是说:“sun.*”包并不是API公开接口的一部分,调用“sun”包的程序并不能确保工作在所有Java平台上,事实上,这样的程序并不能工作在今后的Java平台上。
5.1 保证 rt.jar 和 jce.jar 在 lib 中
首先,从 JDK8 安装目录jrelib 把 jce.jar 和 rt.jar 拷贝到 项目根目录lib;
另外,从 JDK8 安装目录lib 把 tools.jar 拷贝到 项目根目录lib;
然后,把这 3 个 lib 加入到本地依赖中,和之前 2 次的操作相似
5.2 编辑POM文件
关键的是这一段:
<compilerArguments>
<bootclasspath>${project.basedir}/lib/rt.jar;${project.basedir}/lib/jce.jar;${project.basedir}/lib/tools.jar</bootclasspath>
</compilerArguments>
完整的 build 标签如下:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
<compilerArguments>
<bootclasspath>${project.basedir}/lib/rt.jar;${project.basedir}/lib/jce.jar;${project.basedir}/lib/tools.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<!-- JUnit 5 requires Surefire version 2.22.0 or higher -->
<version>2.22.2</version>
</plugin>
</plugins>
</build>
参考博客 Maven编译项目显示 程序包com.sun.*包不存在 【原因及三种解决方案】
参考博客 maven编译时javax.crypto程序包不存在的错误
参考博客 “程序包com.sun.tools.javac.util不存在” 问题解决