Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow configuration of AutoFactory to use custom instantiator instead of new #872

Open
lacasseio opened this issue Aug 27, 2020 · 3 comments

Comments

@lacasseio
Copy link
Contributor

Gradle recommends using ObjectFactory#newInstance to create new instances of classes as it performs a runtime decoration on the classes. It takes the class to instantiate as the first argument and all of the @Inject annotated constructor arguments as the following arguments.

Unfortunately, AutoFactory is opinionated to use new (with good reason). I'm wondering if we could accommodate cases such as this one where a custom instantiator could be used instead of using new. I would rather not have to maintain a fork of this processor.

Is this something this project would accept as a contribution? If so, which design should we go for? It would be nice to @Provided the instantiator class so it can be used automatically.

@lacasseio
Copy link
Contributor Author

lacasseio commented Aug 27, 2020

I played a bit with this in my code base and I came up with the following design that seems to be clean enough to support this requirement:

  1. Add an attribute to @AutoFactory annotation to specify the instantiator class to use, ex:
@AutoFactory(instantiator = MyCustomInstantiator.class)
class Foo { /* ... */ }
  1. The processor will add an additional constructor argument for Provider<MyCustomInstantiator>, ex:
public FooFactory(/* ... */Provider<MyCustomInstantiator> _autoFactory_instantiator) {
    /* ... */
    this._autoFactory_instantiator = _autoFactory_instantiator;
}
  1. The create methods get the instantiator provider and use an expected method newInstance (for example) by passing the class to instantiate as the first parameter and all the arguments as follow-up arguments, ex:
public Foo create() {
    return checkNotNull(_autoFactory_instantiator.get()).newInstance(Foo.class/*, ... */);
}

We can either expect the instantiator to implement an AutoFactory-specific interface or use as-is any object that fit the expected interface aka

<T> T newInstance(Class<T> type, Object... args);

Using instantiator object as-is has the advantage that we can inject current instantiators such as the ObjectFactory from Gradle as it complies with the above interface.

This feature would greatly reduce boilerplate code as well as mostly eliminate out-of-sync issues of those dynamic instantiators between the instantiation point and the constructor arguments list by allowing compile-time failures.

@netdpb
Copy link
Member

netdpb commented Aug 27, 2020

In your paragraph 2, that constructor is supposed to be for FooFactory, not Foo—right?

@lacasseio
Copy link
Contributor Author

@netdpb You are right, my mistake. I made an edit to avoid confusion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants