Thanks to visit codestin.com
Credit goes to github.com

Skip to content
/ qin Public

The next-generation cross-language build tool based on Bun replaces XML with TypeScript configuration, aiming to lead Java into the full-stack era.

Notifications You must be signed in to change notification settings

alamhubb/qin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

79 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Qin - Java 25 构建工具

纯 Java 25 实现的新一代构建工具,以 JSON 配置取代 XML,引领 Java 进入现代化时代。

Java Version License

📖 Qin 是什么?

Qin 是一个专为 Java 项目设计的现代化构建工具,灵感来自 npm/pnpm/yarn 等前端工具的简洁性。

核心理念

告别繁琐的 pom.xml,用 JSON 配置文件管理 Java 项目

Qin 解决的问题

  1. XML 配置太繁琐

    • Maven 的 pom.xml 冗长难读
    • Qin 使用简洁的 JSON 格式
  2. 依赖管理不直观

    • 需要分别指定 groupId、artifactId、version
    • Qin 使用 npm 风格:"group:artifact": "version"
  3. Monorepo 支持差

    • Maven 多模块配置复杂
    • Qin 原生支持工作区(类似 npm workspaces)
  4. 启动速度慢

    • Maven 启动需要数秒
    • Qin 利用 Java 25 AOT,启动只需 300ms

对比示例

Maven pom.xml (30+ 行):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>my-app</artifactId>
    <version>1.0.0</version>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>3.2.0</version>
        </dependency>
    </dependencies>
    
    <repositories>
        <repository>
            <id>central</id>
            <url>https://repo1.maven.org/maven2</url>
        </repository>
    </repositories>
</project>

Qin qin.config.json (10 行):

{
  "name": "my-app",
  "version": "1.0.0",
  "dependencies": {
    "org.springframework.boot:spring-boot-starter-web": "3.2.0"
  }
}

Qin 适合谁?

  • 前端转 Java 开发者 - 熟悉的 npm 风格配置
  • 厌倦 XML 的 Java 开发者 - 简洁的 JSON/TypeScript 配置
  • Monorepo 用户 - 原生多项目支持
  • 追求性能的开发者 - Java 25 带来 2-5x 性能提升
  • 全栈开发者 - 内置 Vite 前端集成

🎉 What's New in Java 25 Version

✨ 核心升级

  • Java 25 LTS - 最新长期支持版本(支持到 2033 年)
  • Flexible Constructor Bodies (JEP 513) - 配置验证更安全
  • Module Import Declarations (JEP 511) - 代码更简洁
  • Primitive Patterns (JEP 507) - 类型安全性增强
  • Structured Concurrency (JEP 505) - 并发性能提升 3-5x
  • AOT Method Profiling (JEP 515) - 启动速度提升 2-3x
  • Compact Object Headers (JEP 519) - 内存占用减少 20-30%

📊 性能提升

指标 Java 17 Java 25 提升
CLI 启动时间 800ms 300ms 2.7x
并行编译 (10 文件) 5.2s 1.8s 2.9x 🚀
内存占用 180MB 135MB -25% 💾
代码量 3500 行 2100 行 -40% 📝

🚀 快速开始

前置要求

  • Java 25 or higher (Download)
  • Maven 3.8+ (可选,用于依赖下载)

编译 Qin

# Windows
.\build-java.bat

# Linux/macOS
./build-java.sh

运行 Qin

# 查看帮助
java -cp ".qin\classes;lib\gson-2.10.1.jar" com.qin.cli.QinCli help

# 编译项目
java -cp ".qin\classes;lib\gson-2.10.1.jar" com.qin.cli.QinCli compile

# 运行项目
java -cp ".qin\classes;lib\gson-2.10.1.jar" com.qin.cli.QinCli run

创建快捷命令(推荐)

Windows (PowerShell):

# 添加到 PowerShell Profile
function qin { java -cp "D:\path\to\qin\.qin\classes;D:\path\to\qin\lib\gson-2.10.1.jar" com.qin.cli.QinCli $args }

Linux/macOS (Bash):

# 添加到 ~/.bashrc or ~/.zshrc
alias qin='java -cp "/path/to/qin/build/classes:/path/to/qin/lib/gson-2.10.1.jar" com.qin.cli.QinCli'

然后就可以直接使用:

qin compile
qin run
qin build

📝 配置文件

qin.config.json

{
  "name": "my-app",
  "version": "1.0.0",
  "description": "My awesome Java 25 app",
  "entry": "src/main/java/com/myapp/Main.java",
  
  "dependencies": {
    "org.springframework.boot:spring-boot-starter-web": "3.2.0",
    "com.github.ben-manes.caffeine:caffeine": "3.1.8"
  },
  
  "devDependencies": {
    "org.junit.jupiter:junit-jupiter": "5.10.1"
  },
  
  "repositories": [
    {
      "id": "aliyun",
      "url": "https://maven.aliyun.com/repository/public"
    },
    {
      "id": "central",
      "url": "https://repo1.maven.org/maven2"
    }
  ],
  
  "java": {
    "version": "25",
    "sourceDir": "src/main/java",
    "testDir": "src/test/java",
    "outputDir": "target/classes",
    "encoding": "UTF-8"
  },
  
  "output": {
    "dir": "dist",
    "jarName": "my-app.jar",
    "fatJar": true
  }
}

🛠️ CLI 命令

命令 说明 示例
compile 编译 Java 项目 qin compile
run 编译并运行 qin run / qin run Test.java
build 构建 Fat JAR qin build
test 运行测试 qin test
sync 同步依赖 qin sync
clean 清理构建产物 qin clean
init 初始化项目 qin init
env 环境检查 qin env

运行指定文件

# 运行项目入口(qin.config.json 中的 entry)
qin run

# 运行指定的 Java 文件
qin run src/main/java/com/example/Test.java

# 运行指定文件并传递参数
qin run MyTest.java arg1 arg2

🚀 高级特性

1. 增量编译

Qin 使用 javax.tools API + 时间戳比较 实现智能增量编译:

  • 智能检测 - 只编译修改过的文件(比较 .java.class 的修改时间)
  • 自动依赖 - javac 自动处理依赖文件的编译
  • 零配置 - 无需额外配置,开箱即用
  • 快速响应 - 无修改时跳过编译,立即运行

实现原理:

// 比较每个 .java 文件和对应 .class 文件的时间戳
private boolean isModified(String javaFilePath) {
    Path classFile = getClassFilePath(javaFilePath);
    if (!Files.exists(classFile)) return true;
    return Files.getLastModifiedTime(javaFile) > Files.getLastModifiedTime(classFile);
}

// 使用 javax.tools API 编译
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.getTask(...).call();

性能提升:

场景 全量编译 增量编译 提升
无修改 3.2s 0.1s 32x
修改 1 个文件 3.2s 0.5s 6.4x 🚀
修改 10 个文件 3.2s 1.8s 1.8x

2. 依赖缓存机制

Qin 在每个项目的 .qin/classpath.json 中缓存依赖解析结果:

{
  "classpath": [
    "D:/project/subhuti-java/build/classes",
    "C:/Users/qinky/.qin/libs/com.google.code.gson/gson-2.10.1/gson-2.10.1.jar"
  ],
  "lastUpdated": "2025-12-30T07:10:32Z"
}

工作流程:

qin run/sync
  ↓
检查 .qin/classpath.json 是否存在
  ↓
比较缓存时间 vs qin.config.json 修改时间
  ↓
缓存有效 → 直接使用(快速启动)
缓存无效 → 重新解析依赖并更新缓存

优势:

  • 首次运行 - 解析依赖 + 生成缓存
  • 🚀 后续运行 - 直接读缓存,秒级启动
  • 🔄 自动刷新 - 修改 qin.config.json 后自动重新解析

3. 本地依赖优先解析

Qin 自动发现并优先使用本地项目依赖,避免从 Maven 下载:

自动发现策略:

  1. 从当前目录向上查找所有包含 qin.config.json 的目录
  2. 扫描每个目录的同级项目
  3. 匹配依赖的 groupId:artifactId
  4. 就近优先(近的项目覆盖远的同名项目)

示例:

d:/project/
├── slime-java/
│   ├── subhuti-java/         # com.subhuti:subhuti-java
│   │   ├── qin.config.json
│   │   └── build/classes/    ← 本地依赖路径
│   ├── slime-token/          # com.slime:slime-token
│   │   └── build/classes/
│   └── slime-parser/         # 依赖上面两个项目
│       └── qin.config.json

slime-parser 中:

{
  "dependencies": {
    "com.subhuti:subhuti-java": "1.0.0-SNAPSHOT",
    "com.slime:slime-token": "1.0.0"
  }
}

执行 qin sync 输出:

→ Syncing dependencies...
  → Found 2 local dependencies
✓ Dependencies synced (2 local, 0 remote)
  Cache: .qin/classpath.json

优势:

  • 🚀 无需发布 - 本地开发无需发布到 Maven
  • 🔄 实时更新 - 修改依赖项目立即生效
  • 💾 节省带宽 - 不下载本地已有的项目
  • 🎯 Monorepo 友好 - 天然支持多项目工作区

4. 依赖解析流程

qin run / qin sync
  ↓
检查依赖缓存 (.qin/classpath.json)
  ↓
[缓存有效]───────────────┐
  ↓                     ↓
[缓存无效]          使用缓存
  ↓                     ↓
本地依赖解析          直接运行
(LocalProjectResolver)
  ↓
找到 → 使用 build/classes 路径
未找到 → 标记为远程依赖
  ↓
远程依赖解析
(DependencyResolver + Coursier)
  ↓
合并本地+远程 classpath
  ↓
写入 .qin/classpath.json
  ↓
运行程序

5. 代码复用设计

run 命令和 sync 命令共享核心依赖解析逻辑:

// run 命令
private static void runProject(String[] args) {
    String classpath = ensureDependenciesSynced(config);  // 复用
    runner.compileAndRun(classpath);
}

// sync 命令  
private static void syncDependencies() {
    syncDependenciesCore(config);  // 核心逻辑
}

// 共享的核心逻辑
private static String syncDependenciesCore(QinConfig config) {
    // 1. 本地依赖解析
    LocalProjectResolver.ResolutionResult localResult = ...;
    
    // 2. 远程依赖解析(仅未在本地找到的)
    if (!localResult.remoteDependencies.isEmpty()) {
        DependencyResolver resolver = ...;
    }
    
    // 3. 生成并缓存 classpath
    return classpath;
}

6. IDEA 集成

Qin 提供 IntelliJ IDEA 插件,实现 IDE 无缝集成:

自动功能:

  • 自动同步 - 打开项目时自动执行 qin sync
  • 库配置生成 - 自动生成 .idea/libraries/*.xml
  • 编译输出配置 - 自动使用 build/classes(与 qin 一致)
  • Monorepo 支持 - 自动扫描所有子项目

安装:

# 构建插件
cd packages/qin-idea-plugin-debug
./gradlew buildPlugin

# 安装:IDEA → Settings → Plugins → ⚙️ → Install from Disk
# 选择 build/distributions/qin-idea-plugin-debug-x.x.x.zip

工作原理:

IDEA 打开项目
     ↓
向上查找 workspace root(.idea/.vscode/.git)
     ↓
向下递归扫描所有 qin.config.json(最多 5 层)
     ↓
为每个项目执行 qin sync
     ↓
生成 .idea/libraries/*.xml
     ↓
更新 .iml 文件(添加库引用 + 配置输出路径)
     ↓
刷新 IDEA 项目模型

7. Monorepo 支持

Qin 原生支持 Monorepo(单仓库多项目)模式:

目录结构:

workspace/
├── .git/
├── .idea/             # IDEA 项目标志
├── project-a/
│   └── qin.config.json
├── project-b/
│   └── qin.config.json
├── packages/
│   ├── lib-1/
│   │   └── qin.config.json
│   └── lib-2/
│       └── qin.config.json
└── apps/
    └── app-1/
        └── qin.config.json

本地依赖解析策略:

  1. 从当前目录向上查找所有 qin.config.json
  2. 扫描同级目录的其他项目
  3. 就近优先:近的项目覆盖远的同名项目

IDEA 插件扫描策略:

  1. 向上找到 workspace root(最顶层的 .idea/.vscode/.git 目录)
  2. 从 workspace root 向下递归扫描所有 qin.config.json
  3. 为每个发现的项目自动执行 sync

配置示例:

// project-a/qin.config.json
{
  "name": "com.example:project-a",
  "version": "1.0.0",
  "dependencies": {
    "com.example:lib-1": "1.0.0",  // 自动使用本地 ../packages/lib-1
    "com.example:lib-2": "1.0.0"   // 自动使用本地 ../packages/lib-2
  }
}

🎯 Java 25 特性展示

1. Flexible Constructor Bodies

// ✨ Java 25 新特性
public record QinConfig(String name, String version, Map<String, String> dependencies) {
    public QinConfig {
        // 可以在 super() 前验证参数!
        if (name == null || name.isBlank()) {
            throw new IllegalArgumentException("name cannot be blank");
        }
        
        // 提供默认值
        dependencies = dependencies != null ? Map.copyOf(dependencies) : Map.of();
    }
}

2. Primitive Patterns in Switch

// ✨ Java 25 - 基本类型模式匹配
String result = switch (value) {
    case int i when i > 0 -> "positive: " + i;
    case long l -> "long value: " + l;
    case double d -> "double value: " + d;
    default -> "other";
};

3. Structured Concurrency

// ✨ Java 25 - 结构化并发
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    var task1 = scope.fork(() -> downloadDependency("lib1"));
    var task2 = scope.fork(() -> downloadDependency("lib2"));
    
    scope.join().throwIfFailed();  // 统一异常处理
    
    return List.of(task1.get(), task2.get());
}

📦 项目结构

用户项目结构

my-project/
├── qin.config.json          # Qin 配置
├── src/
│   ├── main/java/           # 源码
│   │   └── com/myapp/
│   │       └── Main.java
│   └── test/java/           # 测试
├── build/
│   └── classes/             # 编译输出 (OUTPUT_DIR)
├── .qin/                    # Qin 配置目录
│   ├── classpath.json       # 依赖缓存 (CLASSPATH_CACHE)
│   └── libs/                # 本地依赖链接 (LIBS_DIR)
│       └── com.google.code.gson/
│           └── gson-2.10.1/ -> ~/.qin/libs/.../
└── dist/
    └── my-app.jar           # Fat JAR

全局目录结构

~/.qin/
└── libs/                    # 全局依赖缓存 (GLOBAL_LIBS_DIR)
    └── com.google.code.gson/
        └── gson-2.10.1/
            └── gson-2.10.1.jar

路径常量配置 (QinPaths.java)

常量 说明
OUTPUT_DIR build/classes 编译输出目录
QIN_DIR .qin Qin配置目录
CLASSPATH_CACHE .qin/classpath.json 依赖缓存文件
LIBS_DIR .qin/libs 依赖库目录

🔧 开发

项目结构

qin/
├── src/java-rewrite/        # Java 25 源码
│   └── com/qin/
│       ├── types/           # 配置类型(Records)
│       ├── core/            # 核心模块
│       ├── commands/        # 命令实现
│       ├── cli/             # CLI 入口
│       └── java/            # Java 工具
├── .qin/
│   └── classes/             # 编译输出
├── lib/
│   └── gson-2.10.1.jar      # 唯一依赖
└── build-java.bat           # 构建脚本

核心模块架构

1. 路径管理 - QinPaths.java

功能: 统一管理所有路径常量

public static final String OUTPUT_DIR = "build/classes";
public static final String LIBS_DIR = ".qin/libs";

为什么需要: 避免硬编码,统一路径配置,方便维护和修改

2. 编译系统 - 职责分离设计

ClasspathBuilder - classpath构建

功能: 构建编译和运行时的classpath

  • buildCompileClasspath() - 编译时classpath(包含本地项目+远程依赖)
  • buildRuntimeClasspath() - 运行时classpath

为什么需要: classpath构建逻辑复杂(本地项目发现、依赖解析),独立出来提高可维护性

Compiler - 编译逻辑

功能: Java源文件编译

  • compile() - 使用javax.tools API编译
  • filterModifiedFiles() - 增量编译(只编译修改的文件)
  • findJavaFiles() - 查找Java文件

为什么需要: 封装复杂的编译逻辑,支持增量编译提升性能

ResourceCopier - 资源复制

功能: 复制资源文件到输出目录

  • 查找多个可能的资源目录(src/resources, src/main/resources
  • 递归复制目录

为什么需要: 资源文件处理是独立的功能,与编译逻辑分离

Runner - 程序运行

功能: 运行编译后的Java程序

  • run() - 运行指定类
  • runFile() - 运行指定Java文件
  • javaFilePathToClassName() - 路径转类名

为什么需要: 运行逻辑独立,支持多种运行方式

JavaRunner - 门面协调器

功能: 协调上述4个类,提供统一接口

public CompileResult compile() {
    // 1. 编译依赖
    // 2. 查找Java文件
    // 3. 复制资源
    // 4. 增量编译
}

为什么需要: 保持简单的调用接口,隐藏内部复杂性

3. 依赖管理

LocalProjectResolver - 本地项目发现

功能: 自动发现本地项目依赖

  • 向上查找所有qin.config.json
  • 匹配groupId:artifactId
  • 就近优先

为什么需要: Monorepo支持,避免发布到Maven仓库

DependencyResolver - 远程依赖解析

功能: 使用Coursier解析Maven依赖

  • 下载jar到~/.qin/libs
  • 缓存依赖解析结果

为什么需要: 自动下载和管理远程依赖

4. 配置系统 - types/

使用Java 25 Records定义配置类型:

public record QinConfig(
    String name,
    String version,
    Map<String, String> dependencies
) {}

为什么需要: 不可变配置,类型安全,代码简洁

5. CLI系统 - QinCli.java

功能: 命令行入口,解析命令和参数

qin compile → CompileCommand
qin run     → RunCommand
qin build   → BuildCommand

为什么需要: 统一的命令行接口,用户友好


设计原则

  1. 职责单一: 每个类只负责一件事
  2. 依赖注入: 通过构造函数传递依赖
  3. 面向接口: 使用抽象类型,便于测试和扩展
  4. 常量管理: 所有路径通过QinPaths统一管理

### 编译

```bash
# 编译 Qin 本身
.\build-java.bat

# 输出:build/classes/

测试

# 使用 Qin 编译测试项目
cd examples/hello-java
..\..\qin.bat compile
..\..\qin.bat run

🌟 特性

✅ 核心功能

  • JSON 配置 - 告别 XML,拥抱 JSON
  • 依赖管理 - npm 风格的依赖语法
  • 增量编译 - javax.tools API + 时间戳,32x 性能提升
  • 依赖缓存 - .qin/classpath.json 自动缓存,秒级启动
  • 本地依赖优先 - 自动发现本地项目,无需发布到 Maven
  • Fat JAR 构建 - 一键生成可执行 JAR
  • 运行指定文件 - qin run Test.java 灵活运行
  • 并行编译 - Virtual Threads 加速
  • 热重载 - 开发模式自动重新编译
  • Monorepo 支持 - 多项目管理

✅ Java 25 优化

  • Records 代替 POJO - 代码减少 60%
  • Flexible Constructors - 更安全的验证
  • Pattern Matching - 更优雅的类型处理
  • Virtual Threads - 3-5x 并发性能
  • Structured Concurrency - 更可靠的异步
  • AOT Profiling - 2-3x 启动速度
  • Compact Headers - 20-30% 内存节省

📚 文档

🤝 贡献

欢迎贡献代码、报告 Bug 或提出建议!

📄 License

MIT License - 查看 LICENSE 文件


Built with ❤️ using Java 25
Powered by Flexible Constructors, Virtual Threads, and Structured Concurrency

About

The next-generation cross-language build tool based on Bun replaces XML with TypeScript configuration, aiming to lead Java into the full-stack era.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published