javac相当于“-D”?

时间:2016-01-14 11:09:04

标签: java c++

有没有办法给java编译器一些可以运行的java代码访问的变量?
在C / C ++中,我可以给出编译-DKEY=VALUE,这将导致预处理器的KEY #define等于VALUE。然后我可以在编译时检查这个值,以影响正在编译的代码 我找到java的-D,但是这些值会在java中提供System.getProperty()命令行。我希望在编译时给出一个参数,而不是调用时间。

5 个答案:

答案 0 :(得分:11)

javac

-Akey[=value]

命令行选项,用于将信息传递给annotation processors

答案 1 :(得分:8)

使用java注释,可以动态生成其他代码,可以在命令行上配置。它允许生成更多的源代码,配置文件,xml文件,...主要限制是你只允许(重新)生成新的源文件,你不能修改现有的源文件。

下面是一个简短的教程,介绍如何允许javac命令指定在Java代码中可见的参数。这有用吗? IE浏览器。你可以指定一个布尔选项来禁用代码的某些部分,我很确定这些代码部分可以使用proguard之类的工具删除 - 甚至可以通过javac进行优化。其他用途是指定新版本号。这些用例主要是使用c ++ marcros。

所以,你需要:

  • 一个虚拟注释类,它允许处理器运行。它应该只在您的应用程序中指定一次。
  • 一个处理器类,它将运行上面的虚拟注释,并生成选项类。它还将从javac命令行中读取选项。
  • 用于测试目的的虚拟主类。

在编译Main类之前,您还必须编译处理器文件。这当然仅在修改处理器类时完成。所有这三个文件都在底部。现在编译看起来如下(我在Windows上):

编译处理器:

javac .\com\example\ConfigWritterAnnotationProcessor.java

然后Main.java带有处理器的附加参数:

javac -processor com.example.ConfigWritterAnnotationProcessor -AtextToPrint="Hello World!" -AenablePrint=true ./com/example/Main.java

这就是全部,现在您可以运行Main.class,它将使用在编译期间使用上述参数设置生成的Options类。它看起来如下:

package com.example;
public class Options {
    public static final String textToPrint = "Hello World!";
    public static final boolean enablePrint = true;
}

ProcessorStarterAnnotation.java

package com.example;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE})
public @interface ProcessorStarterAnnotation {
}

Main.java

package com.example;

@ProcessorStarterAnnotation
public class Main {
    public static void main(String[] args) {
      if ( com.example.Options.enablePrint ) {
        System.out.println(com.example.Options.textToPrint);
      }
      else {
        System.out.println("Print disabled");
      }
    }
}

ConfigWritterAnnotationProcessor.java

package com.example;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Map;
import java.util.Set;

@SupportedAnnotationTypes("com.example.ProcessorStarterAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
@SupportedOptions({"textToPrint", "enablePrint"})
public class ConfigWritterAnnotationProcessor extends AbstractProcessor {
  private Map<String,String> options;

  @Override
  public synchronized void init(ProcessingEnvironment processingEnv) {
    super.init(processingEnv);
    options = processingEnv.getOptions();
  }

  @Override
  public boolean process(Set<? extends TypeElement> annotations,
                         RoundEnvironment currentRound) {

    if (!currentRound.processingOver()) {
      // This for-s are because processor is also run on newly created Options class.
      for (TypeElement te : annotations) {
        for (Element e : currentRound.getElementsAnnotatedWith(te)) {
          try {
            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Creating com.example.Options");
            JavaFileObject javaFile = processingEnv.getFiler().createSourceFile("com.example.Options");
            Writer w = javaFile.openWriter();
            try {
              PrintWriter pw = new PrintWriter(w);
              pw.println("package com.example;");
              pw.println("public class Options {");
              pw.println("    public static final String textToPrint = \"" + options.get("textToPrint") + "\";");
              pw.println("    public static final boolean enablePrint = " + options.get("enablePrint") + ";");
              pw.println("}");
              pw.flush();
            } finally {
              w.close();
            }
          } catch (IOException x) {
            processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
                x.toString());
          }
        }
      }
    }
    return false;
  }
}

答案 2 :(得分:2)

Java中没有这样的东西。编译时间常量必须在源代码中声明,据我所知,没有预处理器。

BTW,您可以使用java命令行(-D args)的标志来在运行时初始化java常量,这将模仿您正在寻找的内容。

例如:

class Foo {
    private static final String BAR;
    static {
        String foobar = System.getProperty("foo.bar");
        if(foobar != null && foobar.length()>0) {
            BAR = foobar;
        } else {
            BAR = "somedefaultvalue";
        }
    }
}

使用java Xxx -Dfoo.bar=foobar

进行调用

答案 3 :(得分:1)

由于Java中没有预处理的概念,因此解决方案是设计自己的。

可以考虑使用标准的C预处理器或定制的预处理器并编译预处理的输出,但这样做的缺点是重复文件,因此项目将变得更加复杂,并且来自开发环境的支持会降级(比如跳转到语法错误的能力)。

我的建议是通过注释使用注释来引导自定义预处理器,并在编译之前让它进行替换。

例如,

   public static void main(String[] args) {
      int nDisks = 3;
      doTowers(nDisks, 'A', 'B', 'C');
   }

会变成

   public static void main(String[] args) {
      int nDisks = /*@NDISKS*/ 3 /**/;
      doTowers(nDisks, 'A', 'B', 'C');
   }

然后您的预处理器将有一个定义文件,如

NDISKS 5

转换

中的代码
   public static void main(String[] args) {
      int nDisks = /*@NDISKS*/ 5 /**/;
      doTowers(nDisks, 'A', 'B', 'C');
   }

同样,您可以使用

模拟条件代码编译
     doTowers(topN - 1, from, to, inter);
     /*!PRINT*/
     System.out.println("Disk "
     + topN + " from " + from + " to " + to);
     /**/
     doTowers(topN - 1, inter, from, to);

可以由预处理器(具有类似PRINT OFF的定义)转换为

     doTowers(topN - 1, from, to, inter);
     /*!PRINT
     System.out.println("Disk "
     + topN + " from " + from + " to " + to);
     */
     doTowers(topN - 1, inter, from, to);

您可以使用其他语法,但主要想法是

  • 带注释的代码仍可编译,
  • 预处理器替换是可逆的。

答案 4 :(得分:0)

以这种方式拥有它将违背语言的设计。 KEY做的是它在C / C ++预处理器中实际上用VALUE替换KEY

Java没有预处理器,因此机制不可用。如果你想要“等同”的东西,你必须质疑你的意思。通过不预处理源,它不会真正等效。

另一方面,如果您希望将符号VALUE的值设置为值KEY,则会遇到需要声明符号的问题{ {1}}无论如何要确定它的类型。在这种情况下,它只是另一个具有暗示约束的常量/变量。

这意味着即使使用这样的功能,它也不会实际改变生成的代码,你几乎不会比定义值的启动时间更好。这就是通过java提供参数的原因。