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

Add support for jakarta.inject to core Guice. #1711

Merged
merged 1 commit into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ maven_install(
"com.google.guava:guava:31.0.1-jre",
"commons-logging:commons-logging:1.2",
"javax.inject:javax.inject:1",
"jakarta.inject:jakarta.inject-api:2.0.1",
"javax.persistence:javax.persistence-api:2.2",
"javax.servlet:servlet-api:2.5",
"org.apache.struts:struts2-core:2.5.30",
Expand Down Expand Up @@ -75,6 +76,12 @@ maven_install(
"1",
testonly = True,
),
maven.artifact(
"jakarta.inject",
"jakarta.inject-tck",
"2.0.1",
testonly = True,
),
maven.artifact(
"junit",
"junit",
Expand Down
19 changes: 19 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>
<dependency>
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
Expand Down Expand Up @@ -90,6 +94,21 @@
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<testExcludes>
<!--
Don't compile the jakarta TCK b/c it would clash w/ the javax.inject TCK.
We test it with the Bazel build for now, and basic jakarta functionality is tested
with the JakartaTest in the same package.
-->
<testExclude>**/GuiceJakartaTck.java</testExclude>
</testExcludes>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
Expand Down
1 change: 1 addition & 0 deletions core/src/com/google/inject/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ java_library(
"//third_party/java/error_prone:annotations",
"//third_party/java/jsr305_annotations",
"//third_party/java/jsr330_inject",
"//third_party/java/jakarta_inject",
],
)

Expand Down
26 changes: 13 additions & 13 deletions core/src/com/google/inject/Provider.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,24 @@
* by Guice:
*
* <ul>
* <li>When the default means for obtaining instances (an injectable or parameterless constructor)
* is insufficient for a particular binding, the module can specify a custom {@code Provider}
* instead, to control exactly how Guice creates or obtains instances for the binding.
* <li>An implementation class may always choose to have a {@code Provider<T>} instance injected,
* rather than having a {@code T} injected directly. This may give you access to multiple
* instances, instances you wish to safely mutate and discard, instances which are out of scope
* (e.g. using a {@code @RequestScoped} object from within a {@code @SessionScoped} object), or
* instances that will be initialized lazily.
* <li>A custom {@link Scope} is implemented as a decorator of {@code Provider<T>}, which decides
* when to delegate to the backing provider and when to provide the instance some other way.
* <li>The {@link Injector} offers access to the {@code Provider<T>} it uses to fulfill requests for
* a given key, via the {@link Injector#getProvider} methods.
* <li>When the default means for obtaining instances (an injectable or parameterless constructor)
* is insufficient for a particular binding, the module can specify a custom {@code Provider}
* instead, to control exactly how Guice creates or obtains instances for the binding.
* <li>An implementation class may always choose to have a {@code Provider<T>} instance injected,
* rather than having a {@code T} injected directly. This may give you access to multiple
* instances, instances you wish to safely mutate and discard, instances which are out of
* scope (e.g. using a {@code @RequestScoped} object from within a {@code @SessionScoped}
* object), or instances that will be initialized lazily.
* <li>A custom {@link Scope} is implemented as a decorator of {@code Provider<T>}, which decides
* when to delegate to the backing provider and when to provide the instance some other way.
* <li>The {@link Injector} offers access to the {@code Provider<T>} it uses to fulfill requests
* for a given key, via the {@link Injector#getProvider} methods.
* </ul>
*
* @param <T> the type of object this provides
* @author crazybob@google.com (Bob Lee)
*/
public interface Provider<T> extends javax.inject.Provider<T> {
public interface Provider<T> extends javax.inject.Provider<T>, jakarta.inject.Provider<T> {

/**
* Provides an instance of {@code T}.
Expand Down
3 changes: 2 additions & 1 deletion core/src/com/google/inject/Scopes.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ public Boolean visitNoScoping() {
@Override
public Boolean visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
return scopeAnnotation == Singleton.class
|| scopeAnnotation == javax.inject.Singleton.class;
|| scopeAnnotation == javax.inject.Singleton.class
|| scopeAnnotation == jakarta.inject.Singleton.class;
}

@Override
Expand Down
12 changes: 9 additions & 3 deletions core/src/com/google/inject/internal/Annotations.java
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,9 @@ boolean hasAnnotations(Class<? extends Annotation> annotated) {
}

private static final AnnotationChecker scopeChecker =
new AnnotationChecker(Arrays.asList(ScopeAnnotation.class, javax.inject.Scope.class));
new AnnotationChecker(
Arrays.asList(
ScopeAnnotation.class, javax.inject.Scope.class, jakarta.inject.Scope.class));

public static boolean isScopeAnnotation(Class<? extends Annotation> annotationType) {
return scopeChecker.hasAnnotations(annotationType);
Expand Down Expand Up @@ -402,7 +404,8 @@ public static Annotation findBindingAnnotation(
}

private static final AnnotationChecker bindingAnnotationChecker =
new AnnotationChecker(Arrays.asList(BindingAnnotation.class, Qualifier.class));
new AnnotationChecker(
Arrays.asList(BindingAnnotation.class, Qualifier.class, jakarta.inject.Qualifier.class));

/** Returns true if annotations of the specified type are binding annotations. */
public static boolean isBindingAnnotation(Class<? extends Annotation> annotationType) {
Expand All @@ -416,6 +419,8 @@ public static boolean isBindingAnnotation(Class<? extends Annotation> annotation
public static Annotation canonicalizeIfNamed(Annotation annotation) {
if (annotation instanceof javax.inject.Named) {
return Names.named(((javax.inject.Named) annotation).value());
} else if (annotation instanceof jakarta.inject.Named) {
return Names.named(((jakarta.inject.Named) annotation).value());
} else {
return annotation;
}
Expand All @@ -427,7 +432,8 @@ public static Annotation canonicalizeIfNamed(Annotation annotation) {
*/
public static Class<? extends Annotation> canonicalizeIfNamed(
Class<? extends Annotation> annotationType) {
if (annotationType == javax.inject.Named.class) {
if (annotationType == javax.inject.Named.class
|| annotationType == jakarta.inject.Named.class) {
return Named.class;
} else {
return annotationType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
+ " proxying is initialized to null."
+ " No methods can be called.");

// TODO: user -; ?
// TODO: method.setAccessible(true); ?
// this would fix visibility errors when we proxy a
// non-public interface.
return method.invoke(delegate, args);
Expand Down
1 change: 1 addition & 0 deletions core/src/com/google/inject/internal/InjectorShell.java
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ public void configure(Binder binder) {
binder = binder.withSource(SourceProvider.UNKNOWN_SOURCE);
binder.bindScope(Singleton.class, SINGLETON);
binder.bindScope(javax.inject.Singleton.class, SINGLETON);
binder.bindScope(jakarta.inject.Singleton.class, SINGLETON);
}
}

Expand Down
10 changes: 6 additions & 4 deletions core/src/com/google/inject/internal/MoreTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,9 @@ public static <T> Key<T> canonicalizeKey(Key<T> key) {
/**
* Returns an type that's appropriate for use in a key.
*
* <p>If the raw type of {@code typeLiteral} is a {@code javax.inject.Provider}, this returns a
* {@code com.google.inject.Provider} with the same type parameters.
* <p>If the raw type of {@code typeLiteral} is a {@code javax.inject.Provider} or {@code
* jakarta.inject.Provider}, this returns a {@code com.google.inject.Provider} with the same type
* parameters.
*
* <p>If the type is a primitive, the corresponding wrapper type will be returned.
*
Expand All @@ -91,11 +92,12 @@ public static <T> TypeLiteral<T> canonicalizeForKey(TypeLiteral<T> typeLiteral)
throw new ConfigurationException(errors.getMessages());
}

if (typeLiteral.getRawType() == javax.inject.Provider.class) {
if (typeLiteral.getRawType() == javax.inject.Provider.class
|| typeLiteral.getRawType() == jakarta.inject.Provider.class) {
ParameterizedType parameterizedType = (ParameterizedType) type;

// the following casts are generally unsafe, but com.google.inject.Provider extends
// javax.inject.Provider and is covariant
// javax.inject.Provider & jakarta.inject.Provider and is covariant
@SuppressWarnings("unchecked")
TypeLiteral<T> guiceProviderType =
(TypeLiteral<T>)
Expand Down
23 changes: 14 additions & 9 deletions core/src/com/google/inject/spi/InjectionPoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ private <T> Dependency<T> newDependency(Key<T> key, boolean allowsNull, int para

/** Returns the injected constructor, field, or method. */
public Member getMember() {
// TODO -).
// TODO: Don't expose the original member (which probably has setAccessible(true)).
return member;
}

Expand Down Expand Up @@ -300,7 +300,8 @@ public static InjectionPoint forConstructorOf(TypeLiteral<?> type, boolean atInj
.filter(
constructor ->
constructor.isAnnotationPresent(Inject.class)
|| constructor.isAnnotationPresent(javax.inject.Inject.class))
|| constructor.isAnnotationPresent(javax.inject.Inject.class)
|| constructor.isAnnotationPresent(jakarta.inject.Inject.class))
.collect(Collectors.toList());

Constructor<?> injectableConstructor = null;
Expand Down Expand Up @@ -477,20 +478,21 @@ private static boolean checkForMisplacedBindingAnnotations(Member member, Errors
abstract static class InjectableMember {
final TypeLiteral<?> declaringType;
final boolean optional;
final boolean jsr330;
final boolean specInject;
InjectableMember previous;
InjectableMember next;

InjectableMember(TypeLiteral<?> declaringType, Annotation atInject) {
this.declaringType = declaringType;

if (atInject.annotationType() == javax.inject.Inject.class) {
if (atInject.annotationType() == javax.inject.Inject.class
|| atInject.annotationType() == jakarta.inject.Inject.class) {
optional = false;
jsr330 = true;
specInject = true;
return;
}

jsr330 = false;
specInject = false;
optional = ((Inject) atInject).optional();
}

Expand Down Expand Up @@ -536,6 +538,9 @@ public boolean isFinal() {

static Annotation getAtInject(AnnotatedElement member) {
Annotation a = member.getAnnotation(javax.inject.Inject.class);
if (a == null) {
a = member.getAnnotation(jakarta.inject.Inject.class);
}
return a == null ? member.getAnnotation(Inject.class) : a;
}

Expand Down Expand Up @@ -646,7 +651,7 @@ boolean removeIfOverriddenBy(
InjectableMethod possiblyOverridden = iterator.next();
if (overrides(method, possiblyOverridden.method)) {
boolean wasGuiceInject =
!possiblyOverridden.jsr330 || possiblyOverridden.overrodeGuiceInject;
!possiblyOverridden.specInject || possiblyOverridden.overrodeGuiceInject;
if (injectableMethod != null) {
injectableMethod.overrodeGuiceInject = wasGuiceInject;
}
Expand Down Expand Up @@ -719,7 +724,7 @@ private static Set<InjectionPoint> getInjectionPoints(
Annotation atInject = getAtInject(field);
if (atInject != null) {
InjectableField injectableField = new InjectableField(current, field, atInject);
if (injectableField.jsr330 && Modifier.isFinal(field.getModifiers())) {
if (injectableField.specInject && Modifier.isFinal(field.getModifiers())) {
errors.cannotInjectFinalField(field);
}
injectableMembers.add(injectableField);
Expand Down Expand Up @@ -837,7 +842,7 @@ private static boolean isEligibleForInjection(Method method, boolean statics) {

private static boolean isValidMethod(InjectableMethod injectableMethod, Errors errors) {
boolean result = true;
if (injectableMethod.jsr330) {
if (injectableMethod.specInject) {
Method method = injectableMethod.method;
if (Modifier.isAbstract(method.getModifiers())) {
errors.cannotInjectAbstractMethod(method);
Expand Down