0

I have one listner class 'A', which implements interface 'B' and 'B' extends Serializable class.

Now in class 'A',

  1. If I declare logger as transient as below:

    private final transient Logger logger = LoggerFactory.getLogger(getClass());

then spotbug reports error as below:

logger is transient but isn't set by deserialization
  1. If I declare logger as non-transient

    private final Logger logger = LoggerFactory.getLogger(getClass());

m getting below error:

Make "logger" transient or serializable.

how to resolve this problem ?

Ravi
  • 13
  • 5
  • 1
    Make it static, which [it should be anyway](https://rules.sonarsource.com/java/RSPEC-1312). Deserialized classes don't follow the same init mechanism as instantiating the class in code, so logger will be null. SpotBugs has found a genuine issue for you. This was a NPE waiting to happen. – Michael Jul 20 '22 at 10:52
  • if I made it static, getClass() need to be replaced by className like A.class, will it have any impact ? – Ravi Jul 20 '22 at 11:09
  • If some class extends A (say C) then the class associated with the logger will change from C to A. Very unlikely to matter, but it's not identical. – Michael Jul 20 '22 at 11:16
  • Does this answer your question? [How to handle a Findbugs "Non-transient non-serializable instance field in serializable class"?](https://stackoverflow.com/questions/4861228/how-to-handle-a-findbugs-non-transient-non-serializable-instance-field-in-seria) – pringi Jul 20 '22 at 11:17
  • @pringi I wouldn't consider that a duplicate. – Mark Rotteveel Jul 20 '22 at 13:02

1 Answers1

0

The problem is that deserialization doesn't follow the normal rules of object initialization, so the transient field will not be populated, and instead it will be null.

The simplest solution is to make the field static, so it isn't a member of an instance. However, if you have a reason to make it an instance field, for example if you have a lot of subclasses, and you want your logging to be able to identify the actual class, then you need to make sure the transient field is populated when it is deserialized.

This can be done with either readResolve() or readObject(ObjectInputStream). For example:

private Object readResolve() throws ObjectStreamException {
    logger = LoggerFactory.getLogger(getClass());
    return this;
}

or

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    in.defaultReadObject()
    logger = LoggerFactory.getLogger(getClass())
}

In both cases, the field logger can no longer be final.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197