-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from flipkart-incubator/guige-bridge
Guice bridge
- Loading branch information
Showing
11 changed files
with
497 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,7 +40,6 @@ | |
<version>4.12</version> | ||
<scope>test</scope> | ||
</dependency> | ||
|
||
</dependencies> | ||
|
||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
tef-impl/src/main/java/flipkart/tef/guicebridge/GuiceBridgeModule.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package flipkart.tef.guicebridge; | ||
|
||
import com.google.inject.AbstractModule; | ||
import com.google.inject.Injector; | ||
import com.google.inject.Provides; | ||
|
||
/** | ||
* Guice module to setup common infra for the bridge to work | ||
* Date: 1/06/22 | ||
*/ | ||
public class GuiceBridgeModule extends AbstractModule { | ||
|
||
private final TefGuiceScope scope; | ||
|
||
public GuiceBridgeModule() { | ||
this.scope = new TefGuiceScope(); | ||
} | ||
|
||
@Override | ||
protected void configure() { | ||
bindScope(TefRequestScoped.class, this.scope); | ||
bind(TefGuiceScope.class).toInstance(scope); | ||
} | ||
|
||
@Provides | ||
public InjectDataGuiceMembersInjector provideInjectDataGuiceMembersInjector(Injector injector){ | ||
return new InjectDataGuiceMembersInjector(injector); | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
tef-impl/src/main/java/flipkart/tef/guicebridge/InjectDataGuiceMembersInjector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package flipkart.tef.guicebridge; | ||
|
||
import com.google.inject.Injector; | ||
import com.google.inject.Key; | ||
import com.google.inject.MembersInjector; | ||
import flipkart.tef.exception.TefExecutionException; | ||
import flipkart.tef.execution.InjectableValueProvider; | ||
|
||
import java.lang.reflect.Field; | ||
|
||
/** | ||
* MemberInjector to inject the actual value on fields annotated with @DataInject. | ||
* @see TypeListenerForDataInjection for usage pattern | ||
* | ||
* Date: 31/05/22 | ||
*/ | ||
public class InjectDataGuiceMembersInjector<T> implements MembersInjector<T> { | ||
private Field field; | ||
private String injectionName; | ||
private final Injector injector; | ||
|
||
// package-private to let only the type listener create an instance | ||
InjectDataGuiceMembersInjector(Injector injector){ | ||
this.injector = injector; | ||
} | ||
|
||
public void setField(Field field) { | ||
this.field = field; | ||
this.field.setAccessible(true); | ||
} | ||
|
||
public void setInjectionName(String injectionName) { | ||
this.injectionName = injectionName; | ||
} | ||
|
||
@Override | ||
public void injectMembers(T instance) { | ||
try { | ||
InjectableValueProvider valueProvider = injector.getScopeBindings().get(TefRequestScoped.class) | ||
.scope(Key.get(InjectableValueProvider.class), null).get(); | ||
field.set(instance, valueProvider.getValueToInject(field.getType(), injectionName)); | ||
} catch (IllegalAccessException | TefExecutionException e) { | ||
throw new RuntimeException("Exception while injecting members in tef-guice bridge", e); | ||
} | ||
} | ||
} |
47 changes: 47 additions & 0 deletions
47
tef-impl/src/main/java/flipkart/tef/guicebridge/SubclassOrAnnotationMatcher.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package flipkart.tef.guicebridge; | ||
|
||
import com.google.inject.TypeLiteral; | ||
import com.google.inject.matcher.AbstractMatcher; | ||
|
||
import java.io.Serializable; | ||
|
||
import static com.google.common.base.Preconditions.checkNotNull; | ||
|
||
/** | ||
* Guice matcher for matching subclasses using TypeLiteral. | ||
* <p> | ||
* Date: 31/05/22 | ||
*/ | ||
public class SubclassOrAnnotationMatcher extends AbstractMatcher<TypeLiteral<?>> implements Serializable { | ||
/* | ||
Had to re-implement this class instead of using `Matchers.ofSubclass` since it was not based on TypeLiterals. | ||
*/ | ||
private final Class<?> superclass; | ||
|
||
public SubclassOrAnnotationMatcher(Class<?> superclass) { | ||
this.superclass = checkNotNull(superclass, "superclass"); | ||
} | ||
|
||
@Override | ||
public boolean matches(TypeLiteral<?> subclass) { | ||
return subclass.getRawType().isAnnotationPresent(TefRequestScoped.class) | ||
|| superclass.isAssignableFrom(subclass.getRawType()); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object other) { | ||
return other instanceof SubclassOrAnnotationMatcher && ((SubclassOrAnnotationMatcher) other).superclass.equals(superclass); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return 37 * superclass.hashCode(); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "subclassesOf(" + superclass.getSimpleName() + ".class)"; | ||
} | ||
|
||
private static final long serialVersionUID = 0; | ||
} |
56 changes: 56 additions & 0 deletions
56
tef-impl/src/main/java/flipkart/tef/guicebridge/TefGuiceScope.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package flipkart.tef.guicebridge; | ||
|
||
import com.google.common.base.Preconditions; | ||
import com.google.inject.Key; | ||
import com.google.inject.Provider; | ||
import com.google.inject.Scope; | ||
import flipkart.tef.execution.InjectableValueProvider; | ||
|
||
/** | ||
* Custom guice scope (request-scoped) that injects an instance of | ||
* | ||
* @see InjectableValueProvider | ||
* from reuquest (thread-local). Other injections are passed over to creator. | ||
* <p> | ||
* Date: 1/06/22 | ||
*/ | ||
public class TefGuiceScope implements Scope, AutoCloseable { | ||
|
||
private final ThreadLocal<InjectableValueProvider> threadLocal; | ||
|
||
public TefGuiceScope() { | ||
threadLocal = new ThreadLocal<>(); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) { | ||
return new Provider<T>() { | ||
public T get() { | ||
if(key.getTypeLiteral().getRawType().isAssignableFrom(InjectableValueProvider.class)){ | ||
Preconditions.checkState(threadLocal.get() != null, "A scoping block is missing"); | ||
return (T) threadLocal.get(); | ||
} else { | ||
return creator.get(); | ||
} | ||
} | ||
|
||
public String toString() { | ||
return String.format("%s[%s]", creator, "TefRequestScoped"); | ||
} | ||
}; | ||
} | ||
|
||
public String toString() { | ||
return "TefRequestScoped"; | ||
} | ||
|
||
public void open(InjectableValueProvider valueProvider){ | ||
Preconditions.checkState(threadLocal.get() == null, "A scoping block is already in progress"); | ||
threadLocal.set(valueProvider); | ||
} | ||
|
||
@Override | ||
public void close() { | ||
threadLocal.remove(); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
tef-impl/src/main/java/flipkart/tef/guicebridge/TefRequestScoped.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package flipkart.tef.guicebridge; | ||
|
||
|
||
import com.google.inject.ScopeAnnotation; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* Scope annotation for Guice to Tef bridge | ||
* This annotation solves 2 use-cases | ||
* <p> | ||
* 1. Bind the custom scope `TefGuiceScope` | ||
* 2. Marker annotation to be used on the classes where @InjectData needs to be powered by guice | ||
* Date: 1/06/22 | ||
*/ | ||
@Target({ElementType.TYPE, ElementType.METHOD}) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@ScopeAnnotation | ||
public @interface TefRequestScoped { | ||
} |
44 changes: 44 additions & 0 deletions
44
tef-impl/src/main/java/flipkart/tef/guicebridge/TypeListenerForDataInjection.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package flipkart.tef.guicebridge; | ||
|
||
import com.google.inject.TypeLiteral; | ||
import com.google.inject.spi.TypeEncounter; | ||
import com.google.inject.spi.TypeListener; | ||
import flipkart.tef.annotations.InjectData; | ||
|
||
import java.lang.reflect.Field; | ||
|
||
/** | ||
* TypeListener to process instances which are using the @InjectData annotation. | ||
* | ||
* Date: 31/05/22 | ||
*/ | ||
public class TypeListenerForDataInjection implements TypeListener { | ||
|
||
@SuppressWarnings({"rawtypes", "unchecked"}) | ||
@Override | ||
public <I> void hear(TypeLiteral<I> typeLiteral, TypeEncounter<I> typeEncounter) { | ||
Class<?> bizlogicClass = typeLiteral.getRawType(); | ||
|
||
while ((!bizlogicClass.equals(Object.class))) { | ||
Field[] fields = bizlogicClass.getDeclaredFields(); | ||
for (Field field : fields) { | ||
if(field.isAnnotationPresent(InjectData.class)) { | ||
InjectData injectable = field.getAnnotation(InjectData.class); | ||
|
||
/* | ||
Instance of `InjectDataGuiceMembersInjector` is fetched from provider instead of creating via new | ||
to let guice provide a handle to Injector inside `InjectDataGuiceMembersInjector`. | ||
That comes in handy to fetch the requestScopedBinding that is used to | ||
inject the instance of `InjectableValueProvider` | ||
*/ | ||
InjectDataGuiceMembersInjector membersInjector = typeEncounter.getProvider(InjectDataGuiceMembersInjector.class).get(); | ||
membersInjector.setField(field); | ||
membersInjector.setInjectionName(injectable.name()); | ||
typeEncounter.register(membersInjector); | ||
} | ||
} | ||
bizlogicClass = bizlogicClass.getSuperclass(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.