Handle kotlin object declaration with permit annotations.

If the permit annotation is placed before the object keyword then the annotation will be present on the anonymous class. So this change update BoundFieldModule.WithPermits to also check annotations on the anonymous class itself.

PiperOrigin-RevId: 367707010
This commit is contained in:
Guice Team
2021-04-09 14:42:59 -07:00
committed by Guice Team
parent 053d0a5f29
commit e960b66d3d
3 changed files with 33 additions and 16 deletions
@@ -16,6 +16,8 @@
package com.google.inject.testing.fieldbinder;
import static java.util.Arrays.stream;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -42,7 +44,6 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
/**
* A Guice module that automatically adds Guice bindings into the injector for all {@link Bind}
@@ -146,21 +147,27 @@ public final class BoundFieldModule implements Module {
// TODO(user): Enforce this at compile-time (e.g. via ErrorProne).
Preconditions.checkState(
getClass().isAnonymousClass()
&& Arrays.stream(getClass().getAnnotatedSuperclass().getAnnotations())
.anyMatch(
annotation ->
annotation
.annotationType()
.isAnnotationPresent(RestrictedBindingSource.Permit.class)),
&& (hasPermitAnnotation(getClass().getAnnotations())
|| hasPermitAnnotation(getClass().getAnnotatedSuperclass().getAnnotations())),
"This class should only be used as a base class for an anonymous class with"
+ " @RestrictedBindingSource.Permit annotations, for example: new @FooPermit"
+ " BoundFieldModule.WithPermits(instance) {}.");
+ " @RestrictedBindingSource.Permit annotations. For example in Java: `new "
+ " BoundFieldModule.@FooPermit WithPermits(instance) {}` or in Kotlin: "
+ " `@FooPermits object : BoundFiledModule.WithPermits(instance) {}`");
}
@Override
protected void configure() {
install(BoundFieldModule.of(instance));
}
private static boolean hasPermitAnnotation(Annotation[] annotations) {
return stream(annotations)
.anyMatch(
annotation ->
annotation
.annotationType()
.isAnnotationPresent(RestrictedBindingSource.Permit.class));
}
}
private static class BoundFieldException extends Exception {
@@ -1032,15 +1032,10 @@ public class BoundFieldModuleTest extends TestCase {
assertTrue(info.getBindAnnotation().lazy());
}
@RestrictedBindingSource.Permit
@Retention(RetentionPolicy.RUNTIME)
@Target(TYPE_USE)
@interface FooPermit {}
@Qualifier
@RestrictedBindingSource(
explanation = "",
permits = {FooPermit.class})
permits = {TestPermit.class})
@Retention(RetentionPolicy.RUNTIME)
@interface Foo {}
@@ -1051,7 +1046,7 @@ public class BoundFieldModuleTest extends TestCase {
Bindings bindings = new Bindings();
Injector injector =
Guice.createInjector(new BoundFieldModule.@FooPermit WithPermits(bindings) {});
Guice.createInjector(new BoundFieldModule.@TestPermit WithPermits(bindings) {});
assertEquals((Integer) bindings.foo, injector.getInstance(Key.get(Integer.class, Foo.class)));
}
@@ -0,0 +1,15 @@
package com.google.inject.testing.fieldbinder;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.inject.RestrictedBindingSource;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/** Test annotation used to test restricted binding source feature in Kotlin. */
@RestrictedBindingSource.Permit
@Retention(RUNTIME)
@Target({TYPE, TYPE_USE})
public @interface TestPermit {}