10

I am trying to add logging to my interface default method. For example:

@Slf4j // not allowed
interface MyIFace {
    default ThickAndThin doThisAndThat() {
        log.error("default doThisAndThat() called"); 
    }
}

Problem is that I get:

@Slf4j is legal only on classes and enums.

What would be the proper way to deal with this?

pirho
  • 11,565
  • 12
  • 43
  • 70
  • 1
    It would probably be better to `throw UnsupportedOperationException("default doThisAndThat()")` instead of logging error. If the method is not implemented in the class, and gets called, an exception prevents code from continuing as-if nothing went wrong, while logging lets the code silently continue and then maybe someone would eventually read the log and realize that something is horribly wrong with the code. – Andreas Oct 17 '20 at 15:47
  • @Andreas Yes, you are correct about that but actually it was just to log anything, not just error. So my bad that I chose to log **error** :) – pirho Oct 17 '20 at 15:58

2 Answers2

24

You can't use Lombok here because the annotation generates:


private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(YourClass.class);

You can't use private keyword with an interface.

The workaround is to write directly


interface MyIFace {

   org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MyIFace.class);

   default ThickAndThin doThisAndThat() {
     log.error("default doThisAndThat() called"); 
   }

}


Andrei Kovrov
  • 2,087
  • 1
  • 18
  • 28
  • 1
    Yes, I see it now, thanks for the delombok. The only way to do is then to declare it without Lombok and as public. Instead of that I was also thinking to change MyIFace to have method `Logger getLogger()` so that the implementing classes must return what comes with @Slf4j. Advantage is that I get the actual class when logging but on the other hand it then exposes logger of each individual implementing class. So you just can't get a 'perfect' solution with this because of public nature of interface. – pirho Oct 17 '20 at 16:19
  • This further genearted a sonar issue- squid:S1214(Constants should not be defined in interfaces) – iAmLearning Jun 07 '21 at 15:16
  • @pirho in the interface you can do `LoggerFactory.getLogger(getClass());` which will give you a logger for the actual class and not the MyIFace... – Ilario Aug 30 '22 at 15:06
0

With Java 9+ you could use private methods to prevent logger from being public static

public interface MyIFace {
    private Logger log() {
        return LoggerFactory.getLogger(MyIFace.class);
    }

    default void doThisAndThat() {
        log().error("default doThisAndThat() called");
    }
}