From cd5936a856f446d29475ff4a06caa895da091a32 Mon Sep 17 00:00:00 2001 From: GedMarc Date: Sat, 27 Apr 2024 11:53:02 +0200 Subject: [PATCH] 1813 - Allow client definitions for injectable points --- .../google/inject/InjectionPointProvider.java | 12 ++ .../com/google/inject/spi/InjectionPoint.java | 178 ++++++++++-------- 2 files changed, 111 insertions(+), 79 deletions(-) create mode 100644 core/src/com/google/inject/InjectionPointProvider.java diff --git a/core/src/com/google/inject/InjectionPointProvider.java b/core/src/com/google/inject/InjectionPointProvider.java new file mode 100644 index 0000000000..41e91a4fec --- /dev/null +++ b/core/src/com/google/inject/InjectionPointProvider.java @@ -0,0 +1,12 @@ +package com.google.inject; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; + +/** + * A provider for injection points other than jakarta.@Inject or children of + */ +public interface InjectionPointProvider +{ + Class injectionPoint(AnnotatedElement member); +} diff --git a/core/src/com/google/inject/spi/InjectionPoint.java b/core/src/com/google/inject/spi/InjectionPoint.java index 6963328903..b0e87dbe1f 100644 --- a/core/src/com/google/inject/spi/InjectionPoint.java +++ b/core/src/com/google/inject/spi/InjectionPoint.java @@ -23,10 +23,7 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.ObjectArrays; -import com.google.inject.ConfigurationException; -import com.google.inject.Inject; -import com.google.inject.Key; -import com.google.inject.TypeLiteral; +import com.google.inject.*; import com.google.inject.internal.Annotations; import com.google.inject.internal.DeclaredMembers; import com.google.inject.internal.Errors; @@ -34,6 +31,8 @@ import com.google.inject.internal.KotlinSupport; import com.google.inject.internal.Nullability; import com.google.inject.internal.util.Classes; +import jakarta.annotation.Nullable; + import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.AnnotatedType; @@ -42,14 +41,7 @@ import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.function.Predicate; import java.util.logging.Level; import java.util.logging.Logger; @@ -77,13 +69,13 @@ public final class InjectionPoint { this.declaringType = declaringType; this.optional = optional; this.dependencies = - forMember( - new Errors(method), - method, - declaringType, - method.getAnnotatedParameterTypes(), - method.getParameterAnnotations(), - KotlinSupport.getInstance().getIsParameterKotlinNullablePredicate(method)); + forMember( + new Errors(method), + method, + declaringType, + method.getAnnotatedParameterTypes(), + method.getParameterAnnotations(), + KotlinSupport.getInstance().getIsParameterKotlinNullablePredicate(method)); } InjectionPoint(TypeLiteral declaringType, Constructor constructor) { @@ -94,13 +86,13 @@ public final class InjectionPoint { KotlinSupport.getInstance().checkConstructorParameterAnnotations(constructor, errors); this.dependencies = - forMember( - errors, - constructor, - declaringType, - constructor.getAnnotatedParameterTypes(), - constructor.getParameterAnnotations(), - KotlinSupport.getInstance().getIsParameterKotlinNullablePredicate(constructor)); + forMember( + errors, + constructor, + declaringType, + constructor.getAnnotatedParameterTypes(), + constructor.getParameterAnnotations(), + KotlinSupport.getInstance().getIsParameterKotlinNullablePredicate(constructor)); } InjectionPoint(TypeLiteral declaringType, Field field, boolean optional) { @@ -122,19 +114,19 @@ public final class InjectionPoint { errors.throwConfigurationExceptionIfErrorsExist(); boolean allowsNull = - Nullability.hasNullableAnnotation(annotations) - || Nullability.hasNullableAnnotation(typeUseAnnotations) - || KotlinSupport.getInstance().isNullable(field); + Nullability.hasNullableAnnotation(annotations) + || Nullability.hasNullableAnnotation(typeUseAnnotations) + || KotlinSupport.getInstance().isNullable(field); this.dependencies = ImmutableList.>of(newDependency(key, allowsNull, -1)); } private ImmutableList> forMember( - Errors errors, - Member member, - TypeLiteral type, - AnnotatedType[] annotatedTypes, - Annotation[][] parameterAnnotationsPerParameter, - Predicate isParameterKotlinNullable) { + Errors errors, + Member member, + TypeLiteral type, + AnnotatedType[] annotatedTypes, + Annotation[][] parameterAnnotationsPerParameter, + Predicate isParameterKotlinNullable) { List> dependencies = Lists.newArrayList(); int index = 0; @@ -144,9 +136,9 @@ private ImmutableList> forMember( Annotation[] parameterAnnotations = parameterAnnotationsPerParameter[index]; Key key = Annotations.getKey(parameterType, member, parameterAnnotations, errors); boolean isNullable = - Nullability.hasNullableAnnotation(parameterAnnotations) - || Nullability.hasNullableAnnotation(typeAnnotations) - || isParameterKotlinNullable.test(index); + Nullability.hasNullableAnnotation(parameterAnnotations) + || Nullability.hasNullableAnnotation(typeAnnotations) + || isParameterKotlinNullable.test(index); dependencies.add(newDependency(key, isNullable, index)); index++; } catch (ConfigurationException e) { @@ -215,8 +207,8 @@ public TypeLiteral getDeclaringType() { @Override public boolean equals(Object o) { return o instanceof InjectionPoint - && member.equals(((InjectionPoint) o).member) - && declaringType.equals(((InjectionPoint) o).declaringType); + && member.equals(((InjectionPoint) o).member) + && declaringType.equals(((InjectionPoint) o).declaringType); } @Override @@ -249,11 +241,11 @@ public static InjectionPoint forConstructor(Constructor constructor) { * @since 3.0 */ public static InjectionPoint forConstructor( - Constructor constructor, TypeLiteral type) { + Constructor constructor, TypeLiteral type) { if (type.getRawType() != constructor.getDeclaringClass()) { new Errors(type) - .constructorNotDefinedByType(constructor, type) - .throwConfigurationExceptionIfErrorsExist(); + .constructorNotDefinedByType(constructor, type) + .throwConfigurationExceptionIfErrorsExist(); } return new InjectionPoint(type, constructor); @@ -296,15 +288,15 @@ public static InjectionPoint forConstructorOf(TypeLiteral type, boolean atInj Errors errors = new Errors(rawType); List> atInjectConstructors = - Arrays.stream(rawType.getDeclaredConstructors()) - .filter(InjectionPoint::isInjectableConstructor) - .collect(Collectors.toList()); + Arrays.stream(rawType.getDeclaredConstructors()) + .filter(InjectionPoint::isInjectableConstructor) + .collect(Collectors.toList()); Constructor injectableConstructor = null; atInjectConstructors.stream() - .filter(constructor -> constructor.isAnnotationPresent(Inject.class)) - .filter(constructor -> constructor.getAnnotation(Inject.class).optional()) - .forEach(errors::optionalConstructor); + .filter(constructor -> constructor.isAnnotationPresent(Inject.class)) + .filter(constructor -> constructor.getAnnotation(Inject.class).optional()) + .forEach(errors::optionalConstructor); if (atInjectConstructors.size() > 1) { errors.tooManyConstructors(rawType); @@ -329,7 +321,7 @@ public static InjectionPoint forConstructorOf(TypeLiteral type, boolean atInj // Disallow private constructors on non-private classes (unless they have @Inject) if (Modifier.isPrivate(noArgConstructor.getModifiers()) - && !Modifier.isPrivate(rawType.getModifiers())) { + && !Modifier.isPrivate(rawType.getModifiers())) { errors.missingConstructor(type); throw new ConfigurationException(errors.getMessages()); } @@ -344,7 +336,7 @@ public static InjectionPoint forConstructorOf(TypeLiteral type, boolean atInj private static boolean isInjectableConstructor(Constructor constructor) { return constructor.isAnnotationPresent(Inject.class) - || constructor.isAnnotationPresent(jakarta.inject.Inject.class); + || constructor.isAnnotationPresent(jakarta.inject.Inject.class); } /** @@ -454,8 +446,8 @@ public static Set forInstanceMethodsAndFields(Class type) { /** Returns true if the binding annotation is in the wrong place. */ private static boolean checkForMisplacedBindingAnnotations(Member member, Errors errors) { Annotation misplacedBindingAnnotation = - Annotations.findBindingAnnotation( - errors, member, ((AnnotatedElement) member).getAnnotations()); + Annotations.findBindingAnnotation( + errors, member, ((AnnotatedElement) member).getAnnotations()); if (misplacedBindingAnnotation == null) { return false; } @@ -538,7 +530,35 @@ public boolean isFinal() { static Annotation getAtInject(AnnotatedElement member) { Annotation a = member.getAnnotation(jakarta.inject.Inject.class); - return a == null ? member.getAnnotation(Inject.class) : a; + a = a == null ? member.getAnnotation(Inject.class) : a; + //#GedMarc update to allow alternative injection pointers + if(a == null) { + List> annotations = new ArrayList<>(); + ServiceLoader load = ServiceLoader.load(InjectionPointProvider.class); + load.forEach(iPoint -> { + annotations.add(iPoint.injectionPoint(member)); + }); + for (Class annotation : annotations) { + //noinspection ConstantValue + if (a == null) { + a= member.getAnnotation(annotation); + if (a != null) { + a = new Inject(){ + @Override + public Class annotationType() { + return annotation; + } + @Override + public boolean optional() { + return member.isAnnotationPresent(Nullable.class); + } + }; + break; + } + } + } + } + return a; } /** Linked list of injectable members. */ @@ -613,7 +633,7 @@ static class OverrideIndex { * InjectableMethod#overrodeGuiceInject} is set to true */ boolean removeIfOverriddenBy( - Method method, boolean alwaysRemove, InjectableMethod injectableMethod) { + Method method, boolean alwaysRemove, InjectableMethod injectableMethod) { if (position == Position.TOP) { // If we're at the top of the hierarchy, there's nothing to override. return false; @@ -624,8 +644,8 @@ boolean removeIfOverriddenBy( // methods in the parent class. bySignature = new HashMap<>(); for (InjectableMember member = injectableMembers.head; - member != null; - member = member.next) { + member != null; + member = member.next) { if (!(member instanceof InjectableMethod)) { continue; } @@ -648,7 +668,7 @@ boolean removeIfOverriddenBy( InjectableMethod possiblyOverridden = iterator.next(); if (overrides(method, possiblyOverridden.method)) { boolean wasGuiceInject = - !possiblyOverridden.specInject || possiblyOverridden.overrodeGuiceInject; + !possiblyOverridden.specInject || possiblyOverridden.overrodeGuiceInject; if (injectableMethod != null) { injectableMethod.overrodeGuiceInject = wasGuiceInject; } @@ -680,9 +700,9 @@ void add(InjectableMethod injectableMethod) { // Try to reuse the signature we created during removal @SuppressWarnings("ReferenceEquality") Signature signature = - injectableMethod.method == lastMethod - ? lastSignature - : new Signature(injectableMethod.method); + injectableMethod.method == lastMethod + ? lastSignature + : new Signature(injectableMethod.method); bySignature.computeIfAbsent(signature, k -> new ArrayList<>()).add(injectableMethod); } } @@ -698,7 +718,7 @@ void add(InjectableMethod injectableMethod) { * @param errors used to record errors */ private static Set getInjectionPoints( - final TypeLiteral type, boolean statics, Errors errors) { + final TypeLiteral type, boolean statics, Errors errors) { InjectableMembers injectableMembers = new InjectableMembers(); OverrideIndex overrideIndex = null; @@ -735,19 +755,19 @@ private static Set getInjectionPoints( if (atInject != null) { InjectableMethod injectableMethod = new InjectableMethod(current, method, atInject); if (checkForMisplacedBindingAnnotations(method, errors) - || !isValidMethod(injectableMethod, errors)) { + || !isValidMethod(injectableMethod, errors)) { if (overrideIndex != null) { boolean removed = - overrideIndex.removeIfOverriddenBy(method, false, injectableMethod); + overrideIndex.removeIfOverriddenBy(method, false, injectableMethod); if (removed) { logger.log( - Level.WARNING, - "Method: {0} is not a valid injectable method (" - + "because it either has misplaced binding annotations " - + "or specifies type parameters) but is overriding a method that is " - + "valid. Because it is not valid, the method will not be injected. " - + "To fix this, make the method a valid injectable method.", - method); + Level.WARNING, + "Method: {0} is not a valid injectable method (" + + "because it either has misplaced binding annotations " + + "or specifies type parameters) but is overriding a method that is " + + "valid. Because it is not valid, the method will not be injected. " + + "To fix this, make the method a valid injectable method.", + method); } } continue; @@ -775,12 +795,12 @@ private static Set getInjectionPoints( boolean removed = overrideIndex.removeIfOverriddenBy(method, false, null); if (removed) { logger.log( - Level.WARNING, - "Method: {0} is not annotated with @Inject but " - + "is overriding a method that is annotated with @jakarta.inject.Inject." - + "Because it is not annotated with @Inject, the method will not be " - + "injected. To fix this, annotate the method with @Inject.", - method); + Level.WARNING, + "Method: {0} is not annotated with @Inject but " + + "is overriding a method that is annotated with @jakarta.inject.Inject." + + "Because it is not annotated with @Inject, the method will not be " + + "injected. To fix this, annotate the method with @Inject.", + method); } } } @@ -833,8 +853,8 @@ private static Method[] getDeclaredMethods(TypeLiteral type) { */ private static boolean isEligibleForInjection(Method method, boolean statics) { return Modifier.isStatic(method.getModifiers()) == statics - && !method.isBridge() - && !method.isSynthetic(); + && !method.isBridge() + && !method.isSynthetic(); } private static boolean isValidMethod(InjectableMethod injectableMethod, Errors errors) {