What you want is possible!
But not like this. The answer to your actual question is a simple, flat out 'No'. But you don't want what you describe in your question.
Let me elaborate.
Let's first say that you could add methods at runtime. You can't*, but let's say you could.
That would accomplish nothing whatsoever; given:
public class Example implements Singleton<Example> {
@StaticContract Example getInstanceStatic() { return new Example(); }
}
We can already see issues here (this method is.. public. It has to be, that's the rule of interfaces. But given that you want this to be a singleton, that'd be very bad news).
But let's carry on for a moment. The idea is that you want to be able to write, in other code:
Example.instance();
but - how? The compiler won't LET YOU do that, because the method isn't there, and if we go with your plan (of adding the method at runtime), then at compile time it'll never be there, and javac will refuse to compile this. If somehow it DID compile this, then at runtime, where you pull your magic trick and somehow add this method, all would be well, but that's a moot point - short of hacking together a class file with a bytecode editor, there's no way to obtain a class file with the compiled version of Example.instance()
.
You don't want to add this at runtime.
But maybe you want to add it at compile time.
And THAT? That you can do!
Strategy #1: Lombok
Project Lombok lets you write @UtilityClass
which makes it act singleton-esque. Lombok intentionally does not have @Singleton
because as a concept, singletons are so universally deriled as bad code style. I guess you could fork lombok and add it if you must have this.
Strategy #2: Annotation Processors
Other than lombok, annotation processors cannot add things to existing source files. But they can make new ones! Given as actual real bytes on disk source file:
@SingletonizeMe
public class Example {
Example() {} // without lombok you're going to have to write this yourself to ensure nobody outside of the package can instantiate this...
}
then you can write an annotation processor which means that javac will automatically produce this file:
// generated code
package same.pkg.as.your.example;
public class ExampleUtil {
public static final Example EXAMPLE_INSTANCE = new Example();
}
and compile it as part of the build, and any code that contains ExampleUtil.EXAMPLE_INSTANCE
will just be compiled right along, without any complaints. Annotation Processors solve the problem of 'okay, maybe at runtime this would work but how do I explain to javac
to just do what I want without it refusing to compile code that it thinks stands no chance of working at runtime?'.
Strategy #3: Dependency injection systems
From dagger to spring to guice, there are tons of libraries out there that do 'dependency injection', and pretty much all of them have an option to inject things singleton style. Give those 3 libraries a quick look, it should be fairly obvious how that works once you follow their get-started-quick tutorials.
*) You'd think the answer is yes, what with instrumention and the ability to use agent technology to reload a class file. But is that 'adding a method to a class'? No, it is not - it is reloading a class, which does not normally work if you try to add any new members; the hot code replace tech built into VMs doesn't let you change (or add, or remove) any signatures.