使javac从非java依赖项编译

时间:2014-08-06 10:44:29

标签: java javac

目标是以编程方式使用javac(没有其他编译器)来编译扩展另一个类的Java类,该类不作为java源或字节码存在,并且不能作为这些提供。 Java类作为源文件存在,或者作为字符串存在于内存中(我知道如何从字符串编译)。

我认为我需要挂钩查找预编译类。但到目前为止,我无法找到这一部分。因此,如果我知道javac究竟是如何查找预编译的类,我如何能够挂钩并提供我自己的表示,那么这个问题就会得到解答。

或允许我动态提供所需依赖关系的任何其他方式......

修改 由于提到Groovy并且目的受到质疑,让我举一个例子...... 想象一下你在Groovy中有一个名为G的类,有一个类J的字段,它是一个Java类,J扩展了G.我不能编译没有J的G而且我不能编译没有G的J.但是我有G的AST和if我可以用javac连接AST,我将能够编译J然后在Groovy编译器G中 - 或者反过来。目前,这是通过生成存根来绕过的,但我正在寻找更好的解决方案。

编辑2: 使它绝对清楚。这个问题的最终目标是让groovy编译器和javac编译器以某种方式相互通信,它们可以告诉对方是否有某个类,然后让其他编译器知道某个类。让我再说一遍,由于未解析的类,字节码中的存根无法工作。在源头他们的工作,当依赖进口解决至少相似。但是由于Groovy编译器的性质,它实际上类似于javac所处理的东西,我们必须在很早的阶段生成这些源存根,对于大多数可以在groovy中应用的ast变换来说太早了。这是一个问题

3 个答案:

答案 0 :(得分:3)

如果第一个评论是正确的,并且你正在尝试编译当你没有B的源代码或字节码时扩展B的A类,那么我认为答案是“你不能”。如果你考虑编译子类意味着什么,你会发现编译器需要来自超类的细节 - 有什么方法,有什么抽象方法,什么放在跳转表中,什么保护变量和方法可能Java仍然是一种强类型语言(至少在撰写本文时)。

答案 1 :(得分:0)

我可以建议以下内容。你确实不需要提供真实的"基类。你必须提供基类

  1. 根据需要使用相同的完全限定名称。
  2. 如果从子类
  3. 调用它们,则为相同的构造函数
  4. 如果从子类调用或覆盖它们,则使用相同的方法。
  5. 因此,您可以生成满足所有这些要求的类,在类路径中使用此基类编译子类,然后删除此假基类。

    如何创建这样的课程?您可以使用ASM生成源代码并对其进行编译或生成字节代码。

    问题是如何获得类的所有元素:必需的构造函数和超类方法。我不知道Groovy,但我希望你可以使用反射从Groovy类中获取所有这些信息。

    修改

    其他解决方案是使用接口并解耦Groovy和Java代码。只需在Java中定义将从Groovy引用的接口。此接口不具有任何其他依赖项,可以先编译。然后编译Groovy代码。然后编译扩展Groovy类的java类。这有什么问题?

答案 2 :(得分:0)

看起来我现在可以自己回答这个问题了。通过直接使用com.sun.tools.javac.main.JavaCompiler,我可以提供一个Context,我在其中设置了一个自定义的ClassReader。然后可以覆盖loadClass方法,以提供我自己的ClassSymbol。我使用此代码提供ClassSymbol

的类型
        // ClassSymbol cs is from super.loadClass
        // Context context is same as used for creating the compiler
        Type.ClassType newClassType = new Type.ClassType(Type.noType, List.<Type>nil(), cs);
        cs.type = newClassType;
        newClassType.tsym = cs;
        Names names = Names.instance(context);
        Symtab symtab = Symtab.instance(context);
        newClassType.supertype_field = symtab.objectType;
        cs.kind = Kinds.TYP;
        Scope members = new Scope(cs);
        cs.members_field = members;
        Type.MethodType mt = new Type.MethodType(List.<Type>nil(), symtab.voidType, List.<Type>nil(), symtab.methodClass);
        Symbol.MethodSymbol constructor = new Symbol.MethodSymbol(Flags.PUBLIC, names.init, mt, cs);
        members.enter(constructor);

代码将为缺少的类型创建一个幻像类型(扩展Object),并提供不带参数和主体的构造函数。不确定这是不是最好的方法,但让javac运行

已经足够了