Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Imagine you have a software module, which is a plugin to some program (similar to Eclipse) and you want it to have an API which other plugins can call. Your plugin is not freely available, so you want to have a separate API module, which is freely available and is the only thing other plugins need to directly link to - API clients can compile with only the API module, and not the implementation module, on the build path. If the API is constrained to evolve in compatible ways, then client plugins could even include the API module in their own jars (to prevent any possibility of Errors resulting from nonexistent classes being accessed).

Licensing is not the only reason to put API and implementation in separate modules. It could be that the implementation module is complex, with myriad dependencies of its own. Eclipse plugins usually have internal and non-internal packages, where the non-internal packages are similar to an API module (both are included in the same module, but they could be separated).

I've seen a few different alternatives for this:

  1. The API is in a separate package (or group of packages) from the implementation. The API classes call directly into implementation classes. The API cannot be compiled from source (which is desirable in some uncommon cases) without the implementation. It is not easy to predict the exact effects of calling API methods when the implementation is not installed - so clients will usually avoid doing this.

    package com.pluginx.api;
    import com.pluginx.internal.FooFactory;
    public class PluginXAPI {
        public static Foo getFoo() {
            return FooFactory.getFoo();
        }
    }
    
  2. The API is in a separate package, and uses reflection to access the implementation classes. The API can be compiled without the implementation. The use of reflection might cause a performance hit (but reflection objects can be cached if it's a problem. It is easy to control what happens if the implementation is not available.

    package com.pluginx.api;
    public class PluginXAPI {
        public static Foo getFoo() {
            try {
                return (Foo)Class.forName("com.pluginx.internal.FooFactory").getMethod("getFoo").invoke(null);
            } catch(ReflectiveOperationException e) {
                return null;
                // or throw a RuntimeException, or add logging, or raise a fatal error in some global error handling system, etc
            }
        }
    }
    
  3. The API consists only of interfaces and abstract classes, plus a way to get an instance of a class.

    package com.pluginx.api;
    public abstract class PluginXAPI {
        public abstract Foo getFoo();
    
        private static PluginXAPI instance;
        public static PluginXAPI getInstance() {return instance;}
        public static void setInstance(PluginXAPI newInstance) {
            if(instance != null)
                throw new IllegalStateException("instance already set");
            else
                instance = newInstance;
        }
    }
    
  4. The same as above, but the client code needs to get the initial reference from somewhere else:

    // API
    package com.pluginx.api;
    public interface PluginXAPI {
        Foo getFoo();
    }
    
    // Implementation
    package com.pluginx.internal;
    public class PluginX extends Plugin implements PluginXAPI {
        @Override
        public Foo getFoo() { ... }
    }
    
    // Client code uses it like this
    PluginXAPI xapi = (PluginXAPI)PluginManager.getPlugin("com.pluginx");
    Foo foo = xapi.getFoo();
    
  5. Don't. Make clients link directly to the plugin (but still prevent them from calling non-API methods). This would make it difficult for many other plugins (and most open source plugins) to use this plugin's API without writing their own wrapper.

share|improve this question

3 Answers 3

up vote 3 down vote accepted

The answer to your question depends on the definition of "good" in the question "what are some good ways to separate APIs from implementation of ..."

If "good" means "pragmatic easy to implement for you as manufecturer of the api" this might be helpful:

since you are using java where jar-libraries are loaded at runtime i would suggest a slightly different alternative:

  • The API consists only of interfaces plus a dummy implementation of these interfaces that has no real function.

the customer using your api can compile against this dummy-jar and at runtime you can replace the dummy-jar with the licensed one.

something similar is done with slf4j where the actual logging-implementation to be used with your application will be chosen by replacing the logging-jar

share|improve this answer

Have you had a look at the ServiceLoader Mechanisms in Java? Basically you can specify the implementation of an interface via the manifest file in a jar. Oracle also provides some further information about plugins in Java programs.

share|improve this answer

From what I understand people often use the factory pattern for this.

They put the API interfaces into separate module (say a jar file), and then when the clients want to use the API and has access to an implementation of the API, the implementation of the API will have a factory entry point for the clients to start creating concrete objects implementing that API.

This means that your first idea from the above is the closest resemblance.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.