You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用com.sun.codemodel将生成的Java类转为字符串而非写入文件

获取JCodeModel生成的Java类字符串

嘿,这个需求我之前也碰到过!你猜的没错,扩展com.sun.codemodel.CodeWriter就是解决问题的核心——JCodeModel本身没有直接提供获取生成代码字符串的API,但通过自定义CodeWriter,我们可以把生成的代码捕获到内存中,而不是直接写入文件。

下面是具体的实现步骤:

1. 自定义StringCodeWriter类

我们需要创建一个继承自CodeWriter的子类,用Map存储每个生成类对应的源代码字符串,同时处理编码和资源关闭逻辑:

import com.sun.codemodel.CodeWriter;
import com.sun.codemodel.JPackage;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class StringCodeWriter extends CodeWriter {
    // 存储包路径+类名到源代码字符串的映射
    private final Map<String, String> sourceMap = new HashMap<>();

    @Override
    public OutputStream openBinary(JPackage pkg, String fileName) throws IOException {
        // 构建类的唯一标识(包名+文件名)
        String key = pkg.name().isEmpty() ? fileName : pkg.name() + "." + fileName;
        // 使用ByteArrayOutputStream捕获输出
        return new ByteArrayOutputStream() {
            @Override
            public void close() throws IOException {
                super.close();
                // 将字节转换为字符串并存入Map
                sourceMap.put(key, new String(this.toByteArray(), StandardCharsets.UTF_8));
            }
        };
    }

    @Override
    public void close() throws IOException {
        // 无外部资源需要关闭,留空即可
    }

    // 获取指定类的源代码字符串
    public String getSource(String className) {
        return sourceMap.get(className + ".java");
    }

    // 获取所有生成的源代码
    public Map<String, String> getAllSources() {
        return new HashMap<>(sourceMap);
    }
}

2. 使用自定义Writer捕获生成的代码

接下来,用StringCodeWriter代替默认的FileCodeWriter调用JCodeModel的build方法,就能轻松拿到字符串了:

import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JMod;

public class CodeModelDemo {
    public static void main(String[] args) throws Exception {
        JCodeModel codeModel = new JCodeModel();

        // 生成一个简单的Java类示例
        JDefinedClass demoClass = codeModel._class(JMod.PUBLIC, "com.example.DemoClass");
        demoClass.field(JMod.PRIVATE, String.class, "name");
        demoClass.method(JMod.PUBLIC, void.class, "setName")
                .param(String.class, "name")
                .body().assign(demoClass.ref("name"), demoClass.ref("name"));

        // 使用自定义StringCodeWriter
        StringCodeWriter writer = new StringCodeWriter();
        codeModel.build(writer);

        // 获取生成的源代码字符串
        String demoSource = writer.getSource("com.example.DemoClass");
        System.out.println(demoSource);

        // 如果要获取所有生成的类,调用getAllSources()
        writer.getAllSources().forEach((key, source) -> {
            System.out.println("\n--- " + key + " ---");
            System.out.println(source);
        });
    }
}

3. 同时写入文件并获取字符串(可选)

如果你需要同时保留写入文件的操作,还可以实现一个CompositeCodeWriter,同时委托给FileCodeWriter和StringCodeWriter:

import com.sun.codemodel.CodeWriter;
import com.sun.codemodel.JPackage;
import java.io.IOException;
import java.io.OutputStream;

public class CompositeCodeWriter extends CodeWriter {
    private final CodeWriter[] writers;

    public CompositeCodeWriter(CodeWriter... writers) {
        this.writers = writers;
    }

    @Override
    public OutputStream openBinary(JPackage pkg, String fileName) throws IOException {
        OutputStream[] streams = new OutputStream[writers.length];
        for (int i = 0; i < writers.length; i++) {
            streams[i] = writers[i].openBinary(pkg, fileName);
        }
        // 返回一个同时写入多个流的OutputStream
        return new OutputStream() {
            @Override
            public void write(int b) throws IOException {
                for (OutputStream stream : streams) {
                    stream.write(b);
                }
            }

            @Override
            public void close() throws IOException {
                for (OutputStream stream : streams) {
                    stream.close();
                }
            }

            @Override
            public void flush() throws IOException {
                for (OutputStream stream : streams) {
                    stream.flush();
                }
            }
        };
    }

    @Override
    public void close() throws IOException {
        for (CodeWriter writer : writers) {
            writer.close();
        }
    }
}

使用方式也很简单:

// 创建文件写入器和字符串写入器
FileCodeWriter fileWriter = new FileCodeWriter(new File("./generated"));
StringCodeWriter stringWriter = new StringCodeWriter();
// 组合两个写入器
codeModel.build(new CompositeCodeWriter(fileWriter, stringWriter));
// 之后既可以在文件系统看到生成的类,也能通过stringWriter拿到字符串

这个方案完全符合你的需求,既可以替代写入文件的操作,也可以同时保留两种输出方式,而且完全基于JCodeModel的扩展机制,不需要修改框架源码。

内容的提问来源于stack exchange,提问作者Hector

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:23:42