用Intellij idea创建Maven项目JDK8源码阅读环境问题整理

684 阅读4分钟

搭建Java源码阅读环境,有两种类型,一种是调试 Java API 代码,另一种是深入 Java 底层编译 C++ 代码。本文主要还停留在 API 层面,搭建的是阅读 Java API 代码的环境。

本文使用的 JDK 是 1.8.0_131。

创建项目和首次编译:

关于步骤,网上很多可以找到的,我这里就提供两个链接:

创建 Java 项目源码阅读环境 here

创建 Maven 项目源码阅读环境 here

主要流程:

  1. 创建空项目(Java 或者 Maven 项目)
  2. 拷贝安装jdk的目录中拷贝 src.zip 解压到新建的空项目中
  3. 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网站下载 go to OpenJDK

提供给你们 2 个链接:

然后,把这 2 个类文件加入到本地源码项目中:

下载地址由 JDK8源码阅读-WINDOWS下环境搭建 提供!

问题三:com.sun.tools.javac.api不存在

Error:(40, 31) java: 程序包com.sun.tools.javac.api不存在。

1.拷贝 JDK安装目录/lib/tools.jarMaven项目根目录/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>
	<!-- JUnit5 Jupiter -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.7.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 安装目录\jre\lib 把 jce.jar 和 rt.jar 拷贝到 项目根目录\lib; 另外,从 JDK8 安装目录\lib 把 tools.jar 拷贝到 项目根目录\lib; 然后,把这 3 个 lib 加入到本地依赖中,和之前 2 次的操作相似

5.2 编辑POM文件

关键的是这一段配置:

<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>

参考博客 Maven编译项目显示 程序包com.sun.*包不存在 【原因及三种解决方案】

参考博客 maven编译时javax.crypto程序包不存在的错误

参考博客 “程序包com.sun.tools.javac.util不存在” 问题解决

完整的 POM.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.coderead</groupId>
    <artifactId>jdk8-source</artifactId>
    <version>1.0-SNAPSHOT</version>

    <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>

    <dependencies>
        <!-- JUnit Jupiter -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.5.0</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>

    <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>
            <!-- 引入 maven-surefire-plugin 解决 mvn test 运行 Junit5 测试用例时检测不到测试类的问题-->
            <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>

</project>

写了一整天终于完篇了,现在可以去阅读源码了,呼呼呼~