PEP |
004 |
Title |
Topology Definition |
Author |
Epo Jemba [email protected] |
Status |
draft |
Enhance the DX (Developer eXperience) of nuun to allow developpers to easily create applications.
-
First, provide a simple starter from main to handle/hide kernel mechanisms.
-
Then provide a simple way to define the object graph of the application.
Nuun has been designed to supply high level API and SPI to stack/libs/frameworks authors.
This PEP is motivated by the fact that the lambda developer can not use nuun directly, as too many concepts have to be known and mastered before the creation of a minimal application?
The NuunRunner
has to be ran from a simple main of the developper application.
// ...
public static void main(String[] args)
{
NuunRunner.run(MyEntryPoint.class , args);
}
// ...
It takes as first parameter an `EntryPointè class and in second the args from the main.
We’re defining the EntryPoint
in the next section.
We introduce the EntryPoint
annotation which will annotate the application start class.
The application class is just a pojo holder.
@Entrypoint(packageScan="io.nuun.appli1")
public class MyEntrypoint implements Runnable
{
//
}
The EntryPoint
annotation has one mandatory value packageScan
, which indicate the packages in which scanning the classpath.
Basically, the NuunRunner
could be launch from the EntryPoint
.
@EntryPoint(packageScan="io.nuun.appli1")
public class MyApplication
{
public static void main(String[] args)
{
NuunRunner.entrypoint(MyApplication.class).execute(args);
}
}
A Topology is a java interface annotated with @Topologywhich will describe the bindings, AOP of your annotation.
Topologies can compare with spring javaconfig, but topologies are interfaces not POJO.
Topologies are declaratives not imperatives, they do not need to be unit tested (who is unit testing its spring java config class anyway ;p )
We follow an easy to read convention to indicate what to bind, on what key with which qualifiers etc etc.
// a topology with one binding defined
@Topology
public class MyTopology
{
MyServiceImpl injects(MyService key);
}
In this simple example we define that MyService interface will be bound to MyServiceImpl class as implementation.
@EntryPoint(packageScan="io.nuun.appli1")
public class MyApplication
{
@Inject
private MyService myService;
public void run() {
//
myService.doStuff();
}
public static void main(String[] args)
{
NuunRunner.run(MyApplication.class , args);
}
}
A more complete example.
- Topologies methods follow the rule for their name
-
-
injects[a-zA-Z]* : Implementation injects Injection Key. With and Without Qualifier.
-
provides : Provider provides Injection Key
-
intercepts : Interceptor intercepts Class/Method predicate
-
manages : FieldInjector manages Annotation
-
@Topology
public interface MyAppTopology
{
// Constants
@Server
Long port = 8080l;
@Server
String url = "http://localhost.local";
// Simple injection
MyServiceImpl injects (MyService key);
// Qualified injections
HisServiceImpl1 injectsOne (@One HisService key);
HisServiceImpl2 injectsTwo (@Two HisService key);
@Singleton // jsr330
HisServiceImpl3 injectsThree (@Three HisService key);
// auto injection
MyObject injects(MyObject key);
// jsr330 providers
MyService2Provider provides(MyService2 key);
// AOP via AOP Alliance
MyMethodInterceptor intercepts(Predicate<Class<?>> pc, Predicate<Method> pm);
//
MyLoggerFieldInjector manages(MyLogger annotation);
}
This feature will be handle by a plugin that will be declared inside META-INF/services
.