views:

111

answers:

4

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.

+2  A: 

Is there any possibility that these macros might make it into the language?

AFAIK, none whatsoever.

If not, is there any way to run a preprocessor like m4 using Maven?

No doubt there is some way to make this work. Indeed, Maven has plugins for expanding things (e.g. the resource plugin) that could possibly be made to do this kind of thing. If all else fails, you can embed Ant rules in your POM and invoke m4 or similar that way.

But frankly, unless this is a one person private project, I really don't this is worth the problems (and bad mouthing from coworkers) you are likely to get down the track. It is a simple matter to search for occurrences of some log message string in your source code.

Stephen C
The most important thing I want/need is the ability to add `__FILE__` and `__LINE__` concepts to my code. I found a solution that uses java.lang.instrument (http://www.gallot.be/?p=85), but this requires processing the code using `-javaagent`, which appears to be difficult in Java Web Start (we have hundreds of servers with slightly different JNLP files -- no way to include them in signed JARs). I am currently using Maven for management (recent change), but I am going to look at Apache Ivy and going back to Ant.
Ralph
I might be able to do this using the Ant `copy` task with `overwrite="false"` and text replacement. I could then use simple strings containing the markers (maybe "$$__FILE__$$" and "$$__LINE__$$").
Ralph
A: 

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

duffymo
+1  A: 

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?

Don Mackenzie
@Don Mackenzie: Compiler Plugin? `javac` supports these? If so, I might be able to do something with `java.lang.instrument`.
Ralph
Sounds like good fun, perhaps you you could add a follow-up to your answer with how it works out.
Don Mackenzie
A: 

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.

Scott Stanchfield