Skip to content

Commit

Permalink
Reimplemented Wirings using a fresh and simpler approach of a Wiring …
Browse files Browse the repository at this point in the history
…composed of a PropertySourceChain and a FactoryChain

Wirings now support qualifiers and scopes
Wirings now report much more detail when they fail to construct instances
  • Loading branch information
rchodava committed Apr 16, 2017
1 parent f5e5aca commit ef38c25
Show file tree
Hide file tree
Showing 38 changed files with 2,100 additions and 1,728 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package foundation.stack.datamill.configuration;

import rx.functions.Func2;

/**
* A factory for constructing objects of particular types. Use {@link FactoryChains} to create factories and compose
* them together into chains. Note that the contract of a factory is to return a fully constructed instance of the
* requested type (it can use the provided {@link Wiring} to construct the instance, or return null if the factory
* cannot construct an instance.
*
* @author Ravi Chodavarapu (rchodava@gmail.com)
*/
@FunctionalInterface
public interface Factory<T, R extends T> extends Func2<Wiring, Class<? extends T>, R> {
static Factory<?, ?> wrap(TypeLessFactory<?> factory) {
return (w, c) -> factory.call(w);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package foundation.stack.datamill.configuration;

/**
* @author Ravi Chodavarapu (rchodava@gmail.com)
*/
public interface FactoryChain extends QualifyingFactory<Object, Object> {
/**
* Add a factory which will be used to attempt construction of instances for all types.
*/
<T, R extends T> FactoryChain thenForAny(Factory<T, R> factory);

/**
* Add a factory which will be used to attempt construction of instances of concrete classes.
*/
FactoryChain thenForAnyConcreteClass();

/**
* Add a factory for a type, and it's super-classes and interfaces. Note that this factory will be invoked if the
* type requested is exactly the specified type, or one of it's super-classes or interfaces.
*/
<T, R extends T> FactoryChain thenForSuperOf(Class<T> type, Factory<T, R> factory);

/**
* Add a factory for a specific type. Note that this factory is only invoked if the type being constructed matches
* the exact type specified.
*
* @param type Exact type for which the specified factory will be used.
*/
<T, R extends T> FactoryChain thenForType(Class<T> type, Factory<T, R> factory);

/**
* @see #thenForAny(Factory)
*/
<R> FactoryChain thenForAny(TypeLessFactory<R> factory);

/**
* @see #thenForSuperOf(Class, Factory)
*/
<T, R extends T> FactoryChain thenForSuperOf(Class<T> type, TypeLessFactory<R> factory);

/**
* @see #thenForType(Class, Factory)
*/
<T, R extends T> FactoryChain thenForType(Class<T> type, TypeLessFactory<R> factory);

/**
* Add a qualifying factory which will be used to attempt construction of instances for all types.
*
* @see #thenForAny(Factory)
*/
<T, R extends T> FactoryChain thenForAny(QualifyingFactory<T, R> factory);

/**
* Add a qualifying factory for a type, and it's super-classes and interfaces.
*
* @see #thenForSuperOf(Class, Factory)
*/
<T, R extends T> FactoryChain thenForSuperOf(Class<T> type, QualifyingFactory<T, R> factory);

/**
* Add a qualifying factory for a specific type.
*
* @see #thenForType(Class, Factory)
*/
<T, R extends T> FactoryChain thenForType(Class<T> type, QualifyingFactory<T, R> factory);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package foundation.stack.datamill.configuration;

import foundation.stack.datamill.configuration.impl.ConcreteClassFactory;
import foundation.stack.datamill.configuration.impl.FactoryChainImpl;

/**
* @author Ravi Chodavarapu (rchodava@gmail.com)
*/
public class FactoryChains {
/**
* @see FactoryChain#thenForAnyConcreteClass()
*/
public static FactoryChain forAnyConcreteClass() {
return forAny(ConcreteClassFactory.instance());
}

/**
* @see FactoryChain#thenForAny(Factory)
*/
public static <T, R extends T> FactoryChain forAny(Factory<T, R> factory) {
return new FactoryChainImpl(FactoryChainImpl.tautology(), factory);
}

/**
* @see FactoryChain#thenForSuperOf(Class, Factory)
*/
public static <T, R extends T> FactoryChain forSuperOf(Class<T> type, Factory<T, R> factory) {
return new FactoryChainImpl(FactoryChainImpl.isSuperOf(type), factory);
}

/**
* @see FactoryChain#thenForType(Class, Factory)
*/
public static <T, R extends T> FactoryChain forType(Class<T> type, Factory<T, R> factory) {
return new FactoryChainImpl(FactoryChainImpl.isExactType(type), factory);
}

/**
* @see FactoryChain#thenForAny(QualifyingFactory)
*/
public static <T, R extends T> FactoryChain forAny(QualifyingFactory<T, R> factory) {
return new FactoryChainImpl(FactoryChainImpl.tautology(), factory);
}

/**
* @see FactoryChain#thenForSuperOf(Class, QualifyingFactory)
*/
public static <T, R extends T> FactoryChain forSuperOf(Class<T> type, QualifyingFactory<T, R> factory) {
return new FactoryChainImpl(FactoryChainImpl.isSuperOf(type), factory);
}

/**
* @see FactoryChain#thenForType(Class, QualifyingFactory)
*/
public static <T, R extends T> FactoryChain forType(Class<T> type, QualifyingFactory<T, R> factory) {
return new FactoryChainImpl(FactoryChainImpl.isExactType(type), factory);
}

/**
* @see FactoryChain#thenForAny(TypeLessFactory)
*/
public static <R> FactoryChain forAny(TypeLessFactory<R> factory) {
return new FactoryChainImpl(FactoryChainImpl.tautology(), factory);
}

/**
* @see FactoryChain#thenForSuperOf(Class, TypeLessFactory)
*/
public static <T, R extends T> FactoryChain forSuperOf(Class<T> type, TypeLessFactory<R> factory) {
return new FactoryChainImpl(FactoryChainImpl.isSuperOf(type), factory);
}

/**
* @see FactoryChain#thenForType(Class, TypeLessFactory)
*/
public static <T, R extends T> FactoryChain forType(Class<T> type, TypeLessFactory<R> factory) {
return new FactoryChainImpl(FactoryChainImpl.isExactType(type), factory);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
/**
* Used in defining an immediate immutable set of properties.
*
* @see PropertySourceChain
* @see PropertySources
* @author Ravi Chodavarapu (rchodava@gmail.com)
*/
public interface ImmediatePropertySource {
ImmediatePropertySource put(String name, String value);
ImmediatePropertySource put(String name, String format, Object... arguments);
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import java.lang.annotation.*;

/**
* Annotation to be used to add a name qualifier to constructor parameters.
* Annotation to be used to request a named property to be injected into a constructor parameter.
*
* @see Wiring
* @author Ravi Chodavarapu (rchodava@gmail.com)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package foundation.stack.datamill.configuration;

import com.google.common.base.CaseFormat;
import rx.functions.Func1;

/**
* Some common property name transformers that are useful when creating {@link PropertySources}.
*/
public class PropertyNameTransformers { /**
* Transforms from lower-camel case to upper-underscore case, for example: propertyName -> PROPERTY_NAME.
*/
public static final Func1<String, String> LOWER_CAMEL_TO_UPPER_UNDERSCORE =
name -> CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, name);

/**
* Same as calling {@link #leaf(char)} with '/'.
*/
public static final Func1<String, String> LEAF = leaf('/');

/**
* <p>
* Returns a transformation function that applies the first function, and then the second function on the result
* of the first. So compose(LEAF, LOWER_CAMEL_TO_UPPER_UNDERSCORE) will return a function that transforms:
* </p>
* <p>
* category/propertyName -> PROPERTY_NAME
* </p>
*/
public static final Func1<String, String> compose(Func1<String, String> a, Func1<String, String> b) {
return name -> b.call(a.call(name));
}

/**
* <p>
* Returns a transformation function that returns the leaf name of a name separated by the specified separator
* character. For example:
* </p>
* <p>
* leaf('/') returns a function which transforms: category/propertyName -> propertyName
* leaf(':') returns a function which transforms: category:propertyName -> propertyName
* </p>
*/
public static final Func1<String, String> leaf(char separator) {
return name -> {
if (name != null) {
int leafSeparator = name.lastIndexOf('/');
if (leafSeparator > 0) {
return name.substring(leafSeparator + 1);
}
}

return name;
};
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package foundation.stack.datamill.configuration;

import foundation.stack.datamill.values.Value;
import rx.functions.Action1;
import rx.functions.Func1;

import java.util.Optional;

/**
* A source of properties. Use {@link PropertySourceChain} to create {@link PropertySource}s.
* A source of properties. Use {@link PropertySources} to create {@link PropertySource}s.
*
* @author Ravi Chodavarapu (rchodava@gmail.com)
*/
Expand Down Expand Up @@ -34,5 +34,5 @@ public interface PropertySource {
*
* @param propertiesConsumer Lambda that receives this property source.
*/
PropertySource with(Action1<PropertySource> propertiesConsumer);
<R> R with(Func1<PropertySource, R> propertiesConsumer);
}
Loading

0 comments on commit ef38c25

Please sign in to comment.