I'm writing an Aurelia application and I have registered an instance of a class inside the aurelia container. Now, when I authenticate a user, that instance has to be modified. How do I modify the original instance from anywhere in my code?
If you want to follow the dependency injection pattern, you need to inject that instance into any class that wants to modify the instance.
import { inject } from 'aurelia-framework'
import { MyClass } from './my-class';
#inject(MyClass)
export class MyViewModel {
constructor(MyClass) {
this.myClass = MyClass;
}
somethingSpecial() {
this.myClass.foo = 'bar';
}
}
How do I modify the original instance from anywhere in my code
Best that put the instance in a module. And then also expose functions that modify the instance. e.g.
let foo = {}
export function getFoo(){return foo}
export function setFoo(bar){ /* do something */}
Related
I'm trying to bind a class C from a third-party's package.
It injects a class Foo instance via constructor -
class C {
public C(#Inject Foo foo) {
...
}
...
}
In my application, I've two instances of Foo bound -
bind(Foo.class)
.to(FooImpl1.class);
bind(Foo.class)
.annotatedWith(Names.named("SpecialFoo"))
.to(FooImpl2.class);
when C is bound, I want the Named Foo instance to be used. However I do not have access to the code in which C is defined, to be able to put any annotations.
Is there a suggested way of doing that, short of writing my own provider method for C?
You could look into using PrivateModule. In your example, it will be something like:
public class CModule extends PrivateModule {
protected void configure() {
bind(Foo.class).to(FooImpl2.class);
bind(C.class);
expose(C.class);
}
}
I have a Singleton patter class in my Jenkins shared library:
public class Configuration {
private static final INSTANCE = new Configuration()
static getInstance() { return INSTANCE }
private Configuration() {
}
def initialize(env, params) {
Foo = params.FOO;
}
public String Foo = ''
}
Later I can call this from elsewhere using something like this:
Configuration.instance.initialize(env, params);
config = Configuration.instance;
println 'FOO: ' + config.Foo
Ideally, I want the benefit of the Singleton pattern, but I don't want some fields to be overridden by consumers.
First Attempt:
On first thought, I would think this would work:
public class Configuration {
private static final INSTANCE = new Configuration()
static getInstance() { return INSTANCE }
private Configuration() {
}
def initialize(env, params) {
INSTANCE.#Foo = params.FOO;
}
public final String Foo = ''
}
Error:
groovy.lang.GroovyRuntimeException: Cannot set the property 'Foo' because the backing field is final.
Second Attempt:
On Second thought, I would think initializing in the constructor would work, however I don't seem to have access to params and env, unless these are passed in from the vars function, via the initialize() method.
How can I make this Singleton class immutable, or its fields read only?
I think you Could:
Define your class with "implements Serializable", as documentation advices.
Implement the constructor that would accept 1 parameter of type BaseScript, and pass this to it upon instantiation, relative to that this (which you could call internal script) you can refer to script.params, script.env, etc. and I mean you don't HAVE to use initialize, you can do all you want in the c'tor.
But wait, please tell more:
why does CI/CD code need to have a Singleton?
You're passing its data as parameters [so it's not really an immutable entity :)]
Maybe you could "simply" create an immutable map out of your parameters....
Configuration as singleton feels as if you can delegate configuration management to ... configuration management service (consul, etcd, or others).
Please elaborate, it's very curious!
Also you referred to something as "consumers". are these library consumers? or people running the jobs?
Thank you!
I have a global shared library on Jenkins implicitly loaded on all pipelines, then my Jenkinsfile is like that:
new com.company.Pipeline()()
And then the shared library has on directory src/com/company some files, below the Pipeline.groovy class:
package com.company
import static Utils.*
def call() {
// some stuff here...
}
The problem is, this way I have to static declare all methods, thus I lose the context and cannot access jenkins' methods easly without the Pipeline class' instance. As you can see here they passing this to the method mvn.
Thinking of avoid this I was wondering about dynamically add all methods as closures by calling Utils.install this instead of using import static Utils.*, then my Utils.groovy is something like that:
package com.company
private Utils() {}
static def install(def instance) {
def utils = new Utils()
// Some extra check needed here I know, but it is not the problem now
for (def method in (utils.metaClass.methods*.name as Set) - (instance.metaClass.methods*.name as Set)) {
def closure = utils.&"$method"
closure.delegate = instance
instance.metaClass."$method" = closure
}
}
def someMethod() {
// here I want to use sh(), tool(), and other stuff freely.
}
But it raises an GStringImpl cannot be cast to String error, I believe .& do not work with variables, how can I convert a method into closure having the method name on a variable? I have the MetaMethod mostly being a CachedMethod instance, if it were possible to turn it a ClosureMetaMethod instance maybe the problem can be solved, but whenever I search for method to closure conversion for groovy I just found the .& solution!
If I use instance.metaClass.someMethod = utils.&someMethod it do work, but I want it to be dinamic as I add new methods without needing to worry about sharing it.
There is a way to do it dynamically. Notation utils.&someMethod returns a MethodClosure object that can be simply instantiated with its constructor:
MethodClosure(Object owner, String method)
Consider following example:
class Utils {
def foo() {
println "Hello, Foo!"
}
def bar() {
println "Hello, Bar!"
}
}
class Consumer {
}
def instance = new Consumer()
def utils = new Utils()
(utils.metaClass.methods*.name - instance.metaClass.methods*.name).each { method ->
def closure = new MethodClosure(utils, method)
closure.delegate = instance
instance.metaClass."$method" = closure
}
instance.foo() // Prints "Hello, Foo!"
instance.bar() // Prints "Hello, Bar!"
In this example I use def closure = new MethodClosure(utils, method) to get object method reference and then add this method to instance object. I hope it helps.
I'm writing an Angular2 app. Consider a class Cat which I instantiate many instances of, which has an API method to write itself out:
class Cat {
constructor(private name: string) { }
public write() {
Api.write(this); // <== how do I do this?
}
}
The Cat#write method needs to access an API service wrapped around Http:
#Injectable()
class Api {
constructor(private http: Http) { }
write(data) {
this.http.post(...);
}
}
The (perhaps trivially simple) problem I have is how to access API#write from within my Cat class. Since I need the Cat constructor to pass in the name, I can't use it for injection. So how do I make the API#write available to it? Is there some way to access the singleton instance of Api? In that case, who would be in charge of instantiating the singleton instance?
I played around with a static API class but this obviously doesn't work, since injection is into instances, not static classes.
What basic design pattern am I missing here?
I've been struggling with this for a while as well. I did come up with sort of a solution, but it feels hacky.
I use a singleton AppInjector instance. It is set only once, in the constructor of AppComponent (the bootstrapped component). It is used to resolve dependencies for objects to create.
This AppInjector looks something like this:
export class AppInjector {
private static _INJECTOR: Injector;
public static set INSTANCE(injector: Injector) {
if (!this._INJECTOR) {
this._INJECTOR = injector;
}
}
public static get INSTANCE() : Injector {
return this._INJECTOR;
}
}
And the contructor of the AppComponent looks like this:
constructor(injector: Injector) {
AppInjector.INSTANCE = injector;
}
Now if you have added your Api in the bootstrap function of your application:
bootstrap(AppComponent, [Api]);
You will be able to get this singleton from within the Cat instance like this:
class Cat {
public get _api() : Api {
return AppInjector.INSTANCE.get(Api);
}
constructor(private name: string) { }
public write() {
this._api.write(this);
}
}
Again, this by no means feels like the right solution, and probably against a lot of guidelines in Angular2, but I understand your problem, and would also like a better solution than this, but it works fine now for as it is, and I can happily continue coding
Let us suppose the following situation. There is a global module AppModule, a scoped module ScopedModule, a class Main and a class Foo in an application's main variant. Moreover, there is a debug variant with a module DebugAppModule, a module DebugScopedModule and a class Bar. Only the debug variant may know about Bar.
The main variant contains the following relevant code excerpts.
#Module AppModule { /*..*/ }
#Module(injects=Main.class, addsTo=AppModule.class)
ScopedModule { #Provides Foo provideFoo() { return new Foo(); } }
class Main { scopedGraph = graph.plus(new ScopedModule(this)); }
class Foo { /*..*/ }
// In the entry point of the application
ObjectGraph.create(new AppModule());
The debug variant contains the following relevant code excerpts.
#Module(addsTo=AppModule.class, overrides=true) DebugAppModule { /*..*/ }
#Module(injects=Main.class, addsTo=DebugAppModule.class, overrides=true)
DebugScopedModule { #Provides Foo provideFoo() { return new Bar(); } }
class Bar extends Foo { /*..*/ }
// In the entry point of the application
ObjectGraph.create(new AppModule(), new DebugAppModule());
My research and experimentation revealed that it is not possible to override #Provides-methods in scoped modules, i.e. when plusing a module. See for example How to Mock Dagger Activity Object Graphs. That is, in the debug variant whenever a Foo is injected it still would be a Foo and not a Bar. This makes sense because the class Main has a fixed dependency to ScopedModule (note the new).
It seems to me that there should be a way to inject scoped modules themselves – meta-injection so to say :). That is, AppModule could provide ScopedModule for Main. The problem is that ScopedModule's constructor needs an instance of Main and so AppModule would need to retain an instance of Main and that would not fly (e.g. in an Android-specific context where Main would be an Activity).
So what is the best alternative way to achieve the effect of overriding #Provides-methods when using scoped modules?
With the latest version of Dagger, overriding #Provided methods are not permitted.
I found a good solution here. Thanks to #vaughandroid
Basically,
When you are providing your module into your component, you can override your methods.
MyComponent component = DaggerMyComponent.builder()
.appModule(new AppModule() {
#Override public Foo provideFoo() {
return new Bar();
}
})
.build();
This has worked for me and I guess it'll work for you.