Sinobu

Usage

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import org.junit.jupiter.api.Test;
import kiss.Extensible;
import kiss.I;

public class ExtensionTest {

    /**
     * This is extension point.
     */
    interface Codec<T> extends Extensible {

        String encode(T value);
    }

    /**
     * This is extension with LocalDate key.
     */
    class LocalDateCodec implements Codec<LocalDate> {

        public String encode(LocalDate value) {
            return DateTimeFormatter.ISO_DATE.format(value);
        }
    }

    /**
     * Load all extensions once at application's entry point.
     */
    static {
        I.load(ExtensionTest.class);
    }

    /**
     * User code.
     */
    @Test
    void usage() {
        // find extension by type
        Codec<LocalDate> codec = I.find(Codec.class, LocalDate.class);
        assert codec.encode(LocalDate.of(2022, 11, 11)).equals("2022-11-11");
    }
}

Extension Point

Sinobu has a general-purpose plug-in mechanism for extending application functions. An extensible place is called Extension Point, and its substance is a type (interface or class) marked with the Extensible interface.

We give a definition of Extension Point like the following.

interface ThisIsExtensionPoint extends Extensible {
}
class ThisIsAlsoExtensionPoint implements Extensible {
    // This class is both Extension Point and Extension.
}
interface ThisIsNotExtensionPoint extends ThisIsExtensionPoint {
}

In the usage example, Codec is the extension point that converts any object to a string representation.

interface Codec<T> extends Extensible {
    String encode(T value);
}

Extension

We give a definition of Extension like the following.

  • It implements any Extension Point or is Extension Point itself.
  • It must be concrete class and has a suitable constructor for Sinobu (see also I#make(Class) method).
class ThisIsExtension implements Extensible {
    // This class is both Extension Point and Extension.
}
class ThisIsAlsoExtension extends ThisIsExtension {
    // But not Extension Point.
}
class ThisIsNotExtension extends ThisIsExtension {

    public ThisIsNotExtension(NotInjectable object) {
        // because of invalid constructor
    }
}

In the usage example, LocalDateCodec is the extension that is special implementation for LocalDate.

class LocalDateCodec implements Codec<LocalDate> {

    public String encode(LocalDate value) {
        return DateTimeFormatter.ISO_DATE.format(value);
    }
}

Extension Key

You can provide Extension Key for each Extensions by using parameter.

interface ExtensionPointWithKey<K> extends Extensible {
}
class ExtensionWithStringKey implements ExtensionPointWithKey<String> {
    // Associate this Extension with String class.
}
class ExtensionWithListKey implements ExtensionPointWithKey<List> {
    // Associate this Extension with List interface.
}

The key makes easy finding an Extension you need (see also I#find(Class, Class)).

void findExtensionByKey() {
    assert I.find(ExtensionPointWithKey.class, String.class) instanceof ExtensionWithStringKey;
}

Dynamic Loading

All extensions are not recognized automatically, you have to load them explicitly using I#load(Class).

class ExtensionUser {
    static {
        I.load(ExtensionUser.class);
    }

    // write your code
}
class ApplicationMain {
    public static void main(String[] args) {
        I.load(ApplicationMain.class);

        // start your application
    }
}
Object ModelingJSON