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

搭建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网站下载 OpenJDK

给你们 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>
    <!-- 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 安装目录\jre\lib 把 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不存在” 问题解决

posted @ 2021-02-25 20:19  极客子羽  阅读(1674)  评论(0编辑  收藏  举报