1

I want to separate the api from the implementation, and making implementation module depends on api modules, however I encounter the problem that api actually depends on the implementation and don't know how to proceed.

Api/Builder.java

public interface Builder{
  static Builder create(version) {
    if (version < N) 
      return new subBuilder1()
    else
      return new subBuilder2()
  }
}

Impl/subBuilder1.java

public static class subBuilder1 implements Builder{
  public subBuilder1() {......}
  ......
}

Impl/subBuilder2.java

public static class subBuilder2 implements Builder{
  public subBuilder2() {......}
  ......
}

Builder is an interface and I want to move it into api modules.

subBuilder1 and subBuilder2 are actual implementations, and they are currently in implementation modules.

Since currently implementation module depends on api module, I couldn't move the interface Builder into the api module as Builder actually depends on the subBuilder1 and subBuilder2.

How to solve this problem of API invokes implementation? Will dependency injection work for this case?

1 Answer 1

3

Are you perhaps looking for SPI?

You could consider defining a factory interface in the API module, then implement this factory interface in the impl module and add the corresponding configuration file for SPI.

// api
public interface Builder {
   static Builder create(version) {
      ServiceLoader<BuilderFactory> bfs = ServiceLoader.load(BuilderFactory.class);
      Iterator<BuilderFactory> itr = bfs.iterator();
      if (itr.hasNext()) {
         BuilderFactory bf = itr.next();
         return bf.create(version);
      }
      throw new IllegalStateException();
   }
}

public interface BuilderFactory {
   Builder create(version);
}


// impl

// create [META-INF/services/BuilderFactory's Full classname] in impl module and
// write "DefaultBuilderFactory's full classname"
public class DefaultBuilderFactory implements BuilderFactory {
   Builder create(version) {
      if (xx) {
         return new Builder1;
      }
      return new Builder2;
   }
}

Sign up to request clarification or add additional context in comments.

3 Comments

Note that a modular application does not use META-INF/services. Instead, it looks for provides lines in the module descriptors, and the module containing the service provider interface itself must have a corresponding uses line in its module descriptor.
@VGR in my experience they can work together. The SPI client should indeed use uses, but it can also support META-INF/services files for automatic modules or dependencies on the class path. It doesn't require all of the providers to be modular.
@RobSpoor Certainly, both can be present. But if the application is running using from a jlink’d image or using java -m, META-INF/services/* files will be ignored.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.