Question

I am using Java 1.4 with Log4J.

Some of my code involves serializing and deserializing value objects (POJOs).

Each of my POJOs declares a logger with

private final Logger log = Logger.getLogger(getClass());

The serializer complains of org.apache.log4j.Logger not being Serializable.

Should I use

private final transient Logger log = Logger.getLogger(getClass());

instead?

Was it helpful?

Solution

How about using a static logger? Or do you need a different logger reference for each instance of the class? Static fields are not serialized by default; you can explicitly declare fields to serialize with a private, static, final array of ObjectStreamField named serialPersistentFields. See Oracle documentation

Added content: As you use getLogger(getClass()), you will use the same logger in each instance. If you want to use separate logger for each instance you have to differentiate on the name of the logger in the getLogger() -method. e.g. getLogger(getClass().getName() + hashCode()). You should then use the transient attribute to make sure that the logger is not serialized.

OTHER TIPS

The logger must be static; this would make it non-serializable.

There's no reason to make logger non-static, unless you have a strong reason to do it so.

If you really want to go the transient approach you will need to reset the log when your object is deserialized. The way to do that is to implement the method:

 private void readObject(java.io.ObjectInputStream in) 
   throws IOException, ClassNotFoundException;

The javadocs for Serializable has information on this method.

Your implementation of it will look something like:

 private void readObject(java.io.ObjectInputStream in) 
     throws IOException, ClassNotFoundException {
   log = Logger.getLogger(...);
   in.defaultReadObject();
 }

If you do not do this then log will be null after deserializing your object.

Either declare your logger field as static or as transient.

Both ways ensure the writeObject() method will not attempt to write the field to the output stream during serialization.

Usually logger fields are declared static, but if you need it to be an instance field just declare it transient, as its usually done for any non-serializable field. Upon deserialization the logger field will be null, though, so you have to implement a readObject() method to initialize it properly.

Try making the Logger static instead. Than you don't have to care about serialization because it is handled by the class loader.

These kinds of cases, particularly in EJB, are generally best handled via thread local state. Usually the use case is something like you have a particular transaction which is encountering a problem and you need to elevate logging to debug for that operation so you can generate detailed logging on the problem operation. Carry some thread local state across the transaction and use that to select the correct logger. Frankly I don't know where it would be beneficial to set the level on an INSTANCE in this environment because the mapping of instances into the transaction should be a container level function, you won't actually have control of which instance is used in a given transaction anyway.

Even in cases where you're dealing with a DTO it is not generally a good idea to design your system in such a way that a given specific instance is required because the design can easily evolve in ways that make that a bad choice. You could come along a month from now and decide that efficiency considerations (caching or some other life cycle changing optimization) will break your assumption about the mapping of instances into units of work.

If you want the Logger to be per-instance then yes, you would want to make it transient if you're going to serialize your objects. Log4J Loggers aren't serializable, not in the version of Log4J that I'm using anyway, so if you don't make your Logger fields transient you'll get exceptions on serialization.

Loggers are not serializable so you must use transient when storing them in instance fields. If you want to restore the logger after deserialization you can store the Level (String) indide your object which does get serialized.

There are good reasons to use an instance logger. One very good use case is so you can declare the logger in a super-class and use it in all sub-classes (the only downside is that logs from the super-class are attributed to the sub-class but it is usually easy to see that).

(Like others have mentioned use static or transient).

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