1

I have a problem and I don't know which way to got about it

Say I have two Service Provider Interfaces (SPI)

public interface View{
    display();
}

public interface Logger{
    log(String s);
}

And a Service provider that provides both services i.e

public class LogView implements View, Logger{
    ...
}

The problem is that, when I try to get an instance of the log service via ServiceLoader.load(Logger.class) it's different from the instance created with ServiceLoader.load(View.class). Is there a way to go about it such that I can get the same object instance from both calls?

The idea is that after loading the view as a GUI, I want to be able to log on that same instance of the GUI and not another. As it stand now I'm stuck with two separate instance so the log does show up.

Yemi Kudaisi
  • 163
  • 1
  • 7

1 Answers1

2

A solution has been added together with Java modules, but the caveat is that it only works with explicit modules, i.e. with service declarations in a module-info, rather than a file in META-INF/services.

Then, you can declare a public static T provider() method, to be used instead of a public default constructor, whereas the return type T must be assignable to the service type. When such a method has been declared, the declaring type doesn’t need to be an implementation of T itself, but it’s not an error if it is.

So given the class declarations

package somemodule;

public interface Logger{
    void log(String s);
}
package somemodule;

public interface View{
    void display();
}
package somemodule;

public class LogView implements View, Logger {
    static final LogView INSTANCE = new LogView();
    private LogView() {}

    public static LogView provider() {
        return INSTANCE;
    }

    @Override
    public void display() {
        System.out.println("display");
    }

    @Override
    public void log(String s) {
        System.out.println("log "+s);
    }

}

and a module declaration like

module SomeModule {
    uses somemodule.Logger;
    uses somemodule.View;

    provides somemodule.Logger with somemodule.LogView;
    provides somemodule.View with somemodule.LogView;
}

The following code prints true:

View v = ServiceLoader.load(View.class).findFirst().orElseThrow();
Logger l = ServiceLoader.load(Logger.class).findFirst().orElseThrow();
System.out.println(v == l);
Holger
  • 285,553
  • 42
  • 434
  • 765