How to allow third party to extend classes in my java library

I have a parent class in java with some behavior defined

public class ParentClass {
    public ParentClass() {
        //Do some instantiation
    }

    public void doWork() {
       //Do some behavior defined by the parent class
    }
}

Now I have some other class in my project that uses this. Let's say it is used in main

public class Main {

    public static void main(String [] args) {
        ParentClass parent = new ParentClass();
        parent.doWork();
    }

}

Now let's say that my project is setup as a Library for other developers to use. I want them to be able to extend ParentClass and override the doWork() method to their liking. If the developer can not change the Main class, how can I assure that ChildClass is instantiated in main() instead of ParentClass?

Example of ChildClass

public class ChildClass extends ParentClass {
    public ChildClass() {
        super();
        //Do some more instantiation
    }

    @Override
    public void doWork() {
       super.doWork();
       //Do some more behavior in child class
    }
}

Upvotes: 3

Views: 1558

Answers (5)

user207421
user207421

Reputation: 311002

A library shouldn't have a main class in the first place. Make up your main what it is you're shipping: an application or a library.

Or maybe what you're looking for is the Abstract Factory pattern.

Upvotes: 1

fabian
fabian

Reputation: 82461

You could use java.util.ServiceLoader to load a instance of ParentClass, but there are some things you need to consider:

  • A file needs to be added to the jar that contains the class implementing ParentClass, filename META-INF/services/ParentClass (replace ParentClass with the fully qualified name of the class implemented). For every class implementing ParentClass you need to add a line to this file containing the fully qualified name of the implementing class.
  • All those classes need to support creating the class with a public no-argument constructor.

Example

Your jar

package mypackage;
// used interface here, since in this case there's no reason to use
// a class
// you could use a class here too
public interface ParentClass {
    public void doWork();
}
public class Main {

    public static void main(String [] args) {
        // execute doWork of every ParentClass provided
        for (ParentClass parent : ServiceLoader.load(mypackage.ParentClass.class)) {
            parent.doWork();
        }
    }

}

jar with implementations of ParentClass

package mypackage2;

public class ImplementingClass implements ParentClass {

    @Override
    public void doWork() {
       // Custom implementation
       System.out.println("Hello world");
    }
}

META-INF/services/mypackage.ParentClass

mypackage2.ImplementingClass

Then you only need to add the other jar to your classpath when executing your program.

Upvotes: 1

Hesham Saleh
Hesham Saleh

Reputation: 449

This depends on what you want to achieve, if your library is intended to be used by another 3rd party then most probably your main method would be irrelevant as your JAR package would be bundled in his own JAR, which would only allow for a single main class; his.

This approach may require you to have some trigger to initiate your class (engine?), again, depending on how you intend clients to use your APIs.

Furthermore, you can check the Template Method design pattern as it may be useful for your case, in essence, it allows you to settle the bold lines of your algorithm and define which parts you would like clients to redefine/extend.

Upvotes: 2

Raedwald
Raedwald

Reputation: 48682

No need to rely on your provided main method. If they can extend your class they can create an object of their extending class in their own main method.

Upvotes: 0

M A
M A

Reputation: 72864

Well there seems to be many ways of doing this. One simple way is to have the client pass the name of the child class as a system property. The main can access the class name using System.getProperty("prop.name").

Another way is to use the Services API to look for implementing classes. See https://docs.oracle.com/javase/tutorial/ext/basics/spi.html#the-serviceloader-class.

Having said this, what you described is weird because the client code itself is usually supposed to have its own main.

Upvotes: 1

Related Questions