2

I want all Java classes to have a logger variable:

private static final Logger logger = Logger.getLogger(Foo.class);

But I have to type this line in all classes.

Is there to way to automate this? Can annotations help me in this?

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
user855
  • 19,048
  • 38
  • 98
  • 162
  • Related to http://stackoverflow.com/questions/2154726 ... Don't pay attention to the naysayers in that question. We had several people doing cut'n'paste of the log line and forgetting to change the class name hence we needed a quick'n'dirty way to find these broken inits. Works great. Note that you also may want, by default, to have *equals* and *hashCode* throw an exception because they're, well, broken for anything but the simplest case (no inheritance) but it's unlikely people here would agree (I suggest they go argue with Joshua Bloch and *Effective Java*). – SyntaxT3rr0r Apr 08 '11 at 08:11
  • That is exactly what happened in yesterday's code review! – user855 Apr 08 '11 at 15:53

10 Answers10

6

I guess what you really want in not inheritance. In fact inheritance is a rather bad way to incorporate a logger IMHO, as a logger is not genuinely a feature of a class but rather a cross-cutting concern of the application.

What you need is an adapted new Class template. If you are using eclipse, you can find it in the Preferences under Java->Code Style->Code Templates then switch to the right side of the dialog and select Code->New Java files

In intellij idea you can find the templates under File->Settings->File Templates->Class

The accepted answer to this question demonstrates incorporating log4j logging in a template, complete with import statements.

Community
  • 1
  • 1
kostja
  • 60,521
  • 48
  • 179
  • 224
  • So, you are saying there is no Java way of doing this. I need the help of an IDE – user855 Apr 08 '11 at 06:57
  • 3
    there are many ways in java. The question is not what you can do, but rather what you should do. You could implement universal logging in a multitude of ways - inheritance, reflection, as an aspect, or using code templates, keyboard shortcuts or even a DSL...if you really wanted to that is – kostja Apr 08 '11 at 07:50
  • 1
    You can see code templates as a non-invasive way that does not force your application to use addidtional frameworks or libraries or bad coding practices – kostja Apr 08 '11 at 07:58
5

If you'd like to go the inheritance way, which is IMHO not very good, you could inherit from an abstract base class where a protected non-static Logger is declared like this:

protected final Logger log = Logger.getLogger(getClass().getName());

This way the logger's class will be of the implementing class. But of course there's the problem with Java allowing only single inheritance which might get you in trouble when you need to extend another class.

I, personally, am using AOP (Aspect Oriented Programming) for logging but it's not always a solution.

janhink
  • 4,943
  • 3
  • 29
  • 37
3

Is there to way to automate this?

Certainly not in plain Java.

Inheritance won't solve this problem ... if you want a field that is static and/or private. The closest you could come is adding a method like this to a base class:

    protected final Logger getLogger() {
        return Logger.getLogger(this.getClass());
    }

and that's going to be rather expensive.

Alternatively, you could add a non-private, non-static field to a base class; e.g

    protected final Logger log = Logger.getLogger(this.getClass());

Or you could get your IDE or some source code processor / generator to add a static private Logger field to the source code of each class.

Can annotations help me in this?

I don't think so. You might be able to inject a field using AOP, but I don't think your code would be able to refer to it.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • *but I don't think your code would be able to refer to it* It would work if you use only the aspectj compiler. But if you compile with javac and then weave the classes it isn't possible. – Sean Patrick Floyd Apr 08 '11 at 08:00
  • 1
    That's what I figured. We're effectively talking about a different programming language ... – Stephen C Apr 08 '11 at 11:15
3

If you're using Eclipse, make a new Code Template for Java classes. This will add a logger reference in every new class, including the appropriate import. Adapt the import if you're not talking about log4j.

enter image description here

And then

enter image description here

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
0

use inheritance

inheritance might help you

Nirmal- thInk beYond
  • 11,847
  • 8
  • 35
  • 46
0

Well, what you could do is to create an abstract parent class that owns this logger variable and each of your classes inherits from this class. But as in java there is only a single inheritance allowed, you might get into trouble because the inheritance is blocked by your parent class.

Second problem is: the logger will always be initialized with the class of the abstract parent class. If this doesn't bother you ....

martin
  • 980
  • 1
  • 13
  • 28
0

Learn Dependency Injection, use a framework like Seam (including Weld), Spring or Guice and then use aspect oriented programming (AOP) to automatically log all called methods (and optionally how long that method take).

There are cases where you 'll still want to define the Logger and do some logging inside some methods, but still the AOP approach will remove a lot of your boilerplate code that violates the DRY (Do not repeat yourself) principle.

Geoffrey De Smet
  • 26,223
  • 11
  • 73
  • 120
0

A very primitive solution would be to create an abstract class containing the attritbute you want to add to all your classes. But since java does not support multiple inheritance this solution is not suitable if you need to inherit from other classes.
As far as I know, annotations are not designed to provide such functionality.

rob
  • 2,904
  • 5
  • 25
  • 38
0

Don't do any of this, it's overengineering. Just put a separate logger in each class that needs logging and be done with it.

As a small hack you can leave out the 'private' (making the logger package protected) to avoid the pesky Eclipse 'unused' warnings when there is currently no line of code using your logger, without having to add a SuppressWarnings annotation.

Adriaan Koster
  • 15,870
  • 5
  • 45
  • 60
-3

Your classes should inherit this from a common base class.

I'm no Java guru but something like should be possible

public class Vehicle
{
    protected Logger logger = Logger.getLogger(this.getClass());
}

public class Car extends Vehicle
{
}

That's how it could be done in C# - it's been ages since I last used Java.

Filburt
  • 17,626
  • 12
  • 64
  • 115
  • 3
    That's not possible as each classes `logger` should be different (i.e. `BaseClass` should use `Logger.getLogger(BaseClass.class)` but `ExtendsBase` should use `LOgger.getLogger(ExtendsBase.class)`). – Joachim Sauer Apr 08 '11 at 06:49
  • but in one of the class , he need to extend someother class, then the above process fails. As java does not support multiple inheritence – developer Apr 08 '11 at 06:55
  • this dosenot meet the answer 100% – developer Apr 08 '11 at 06:57
  • You cannot reference `this` from a static context. And there's no function `typeof` – Lukas Eder Apr 08 '11 at 07:05
  • @Joachim The whole problem looks like working around a seriously flawed design. – Filburt Apr 08 '11 at 07:12
  • @Filburt, yes. Static inheritance is not possible in Java. That's the whole point of `static`, it's static where it is declared. You can't override it or anything. Probably C# has a more intuitive understanding of `static` – Lukas Eder Apr 08 '11 at 07:24