-
Notifications
You must be signed in to change notification settings - Fork 179
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
WIP: ConditionalBinder #256
base: master
Are you sure you want to change the base?
Conversation
* <p>Scoping elements independently supported per binding. Use the {@code in} method | ||
* to specify a binding scope. | ||
*/ | ||
public abstract LinkedBindingBuilder<T> whenMatch(Conditional obj); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about adding operators to compose Conditionals (and, or/any, not)? Implementing this explicitly (by wrapping into higher level Conditional object) would be cumbersome, due to the way injections are handled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guice's Matcher has an abstract implementation that includes 'and' and 'or'. We could follow the same pattern here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated the PR with support for AND, OR and NOT operations on conditionals. I also simplified the API by removing the Matcher class and making dependencies required for evaluating a conditional directly injectable into the conditional via member injection.
…njection of any dependency needed by the conditional directly into the conditional. Add AND, OR, NOT operations on conditionals.
* <p>Scoping elements independently supported per binding. Use the {@code in} method | ||
* to specify a binding scope. | ||
*/ | ||
public abstract LinkedBindingBuilder<T> whenNoMatch(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we do this with whenMatch(new DefaultBindingConditional()) or something like that to avoid the special case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a very long and ambiguous way of specifying the default and is not in the sprit of a DSL. DefaultBindingConditional could mean several things, is it the default implementation of a conditional or is it the conditional to use as the default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whenNone is just another conditional though, maybe call it whenMatch(new ConditionalOnNoOtherMatches())?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either way, ConditionalOnNoOtherMatches() would require special handling since it would require knowledge of how all other conditionals have been processed. IMO it's much cleaner to just track this as an explicit special default case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do I do something like whenMatch(Conditional.and(new ConditionOnNoOtherMatches(), new ConditionalOnProfile("prod")) if this is kept as a special case?
…will then be the responsibility of a composite conditional (AndConditional, etc.) to pass the Injector to its children, giving them access to the injector.
…ls class. Rename 'and' to 'allOf', and 'or' to 'anyOf'.
*/ | ||
public interface Conditional { | ||
/** | ||
* Evaluate whether the condition is true. evaluate() is only called once at injector |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
javadoc update
import com.google.inject.Module; | ||
import com.google.inject.Provides; | ||
import com.netflix.governator.spi.PropertySource; | ||
|
||
public class PropertiesPropertySource extends AbstractPropertySource { | ||
public final class PropertiesPropertySource extends AbstractPropertySource implements Module { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gak. Properties is legacy Java with all synchronized methods. Why do we want this in 2016, and not a Map<String,String>?
if (getClass() != obj.getClass()) | ||
return false; | ||
|
||
throw new RuntimeException("Only one PropertiesModule may be installed"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IllegalStateException would be clearer; usually a bad idea to throw RuntimeException
public class AllOfConditional implements Conditional { | ||
private final List<Conditional> children; | ||
|
||
public AllOfConditional(List<Conditional> children) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be able to take any Iterable or Collection as input, and add a varargs constructor too?
import java.util.List; | ||
import java.util.Set; | ||
|
||
import com.google.common.collect.ImmutableList; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to use these google collections classes any more (with Java 8)?
|
||
static <T> ConditionalBinder<T> newRealConditionalBinder(Binder binder, Key<T> key) { | ||
if (binder.currentStage().equals(Stage.PRODUCTION)) { | ||
throw new RuntimeException("ConditionalBinder may not be used in Stage.PRODUCTION. Use Stage.DEVELOPMENT."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IllegalStateException or IllegalArgumentException, take your pick
@Override | ||
public List<Binding<?>> getCandidateElements() { | ||
if (isInitialized()) { | ||
return (List<Binding<?>>) (List<?>) candidateBindings; // safe because bindings is immutable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
double cast?
} | ||
|
||
@Override | ||
public boolean equals(Object o) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems flawed that Condition is not part of the equality check, but is part of the object state and passed in via constructor. I would include at least an identity comparison for Condition here.
/** | ||
* Utility class for creating conditional | ||
*/ | ||
public abstract class Conditionals { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need for 'abstract', it's not instantiable (using java.util.Collections for comparison)
|
||
@Singleton | ||
static class SingletonFoo implements Foo { | ||
static int injectedCount = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
volatile?
I didn't see any unit tests that use the @conditional[Anything]; annotation-based conditionals are supported yes? |
The ConditionalBinder enables specifying multiple candidates for a binding with each having a condition that can be based on configuration or other state. ConditionalBinder follows an implementation very similar to Multibinder in that all bindings are created with custom annotations and are resolved at injector creation time.
For example,
The following situations are not valid and result in a CreationException error at injector creation (not injection) time. The exception will contain detailed information on the candidate bindings and where in code they were bound
Several approaches were considered for implementing this feature, including a Module annotation based approach. The benefits of this approach are,
Drawbacks to this approach are,