Question

I know all of the philosophical arguments against preprocessors and macros in Java. I don't agree that just because some may abuse a language feature, it should be excluded for all.

I would like to include __FILE__ and __LINE__ macros in my Java and Scala code for efficient logging. Any use of Exception is unacceptable because of runtime performance impacts. Those people who argue that logging can be turned off in "production code" should heed the advise of Brian Kernighan:

Removing the error messages "now that the program is working" is like wearing a parachute on the ground, but taking it off once you're in the air.

Is there any possibility that these macros might make it into the language? If not, is there any way to run a preprocessor like m4 using Maven?

Thanks.

Was it helpful?

Solution

Update @ralph Well, this is a question from 2+ years ago, but since I'm having the same need for __LINE__ and __FILE__ and you had mentioned SCALA; here are some ideas I'm having, using Scala macros (as of v2.10.0-RC1)

def $currentPosition:String = macro _currentPosition;
def _currentPosition(c:Context):c.Expr[String]={ import c.universe._;
  val pos = c.enclosingPosition;
  c.Expr(Literal(Constant(
    s"${pos.source.path}: line ${pos.line}, column ${pos.column}" )))
}

Macros being evaluated at compile-time, $currentPosition is replaced with a literal string that describes its position in the source code. For example, put in a println at line 13, it displays:

/sandbox/tmp_juno_workspace2/LogMacro_Test/src/test/Trial.scala: line 13, column 15

I have not played with these mechanisms extensively, but by tweaking the thing, one can develop the logging features (s)he requires (I should add that writing macros can be difficult - it is for me!).

OTHER TIPS

IMHO the "correct" way to achieve this would be to write a compiler plugin to perform the substitution, but is it really worth that amount of effort?

Logging should be a cross-cutting concern, anyway. It's possible to do what you want with aspects.

You can use the compiler API to do this, but be careful. The "rules" for annotation processors/compiler plugins state that they are not supposed to modify the class being generated. Sun/Oracle may enforce this at anytime.

For now, have a peek at http://projectlombok.org. It uses the compiler API to generate getters, setters and so forth. They have source code that you could use as a model, or you could contribute handlers to them.

you could probably do something like the following:

public class Foo {
  @FileName private static String fileName;
  @LineNumber private static int lineNumber;
  ...
  public void foo() {
     log(fileName, lineNumber, "some message");
  }
}

Then have the annotation processor change the fileName and lineNumber references to the actual file/line.

Just be aware that this could break with later JDK versions. I don't know if Sun/Oracle will actually enforce the "don't modify the class being generated" rule, but they could.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top