From eba7e54755ee7636622d1f030e13fa97a60fb0ef Mon Sep 17 00:00:00 2001 From: Konrad Windszus Date: Tue, 27 Jun 2023 19:03:24 +0200 Subject: [PATCH] SLING-11917 Evaluate constructor parameter names via reflection This is available if compiled accordingly (with javac flag -parameters, https://docs.oracle.com/en/java/javase/17/docs/specs/man/javac.html#option-parameters) --- .../models/impl/ModelAdapterFactory.java | 2 +- .../impl/model/ConstructorParameter.java | 27 ++++++++++++------- .../impl/model/ModelClassConstructor.java | 19 +++++-------- .../impl/injectors/SelfInjectorTest.java | 4 +-- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java index 9724013e..02d05415 100644 --- a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java +++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java @@ -1017,7 +1017,7 @@ private RuntimeException setMethod(InjectableMethod injectableMethod, Map parameterValues, Object value) { if (constructorParameter.getParameterType() instanceof Class) { - Result result = adaptIfNecessary(value, (Class) constructorParameter.getParameterType(), constructorParameter.getGenericType()); + Result result = adaptIfNecessary(value, (Class) constructorParameter.getParameterType(), constructorParameter.getType()); if (result.wasSuccessful() ) { parameterValues.set(constructorParameter.getParameterIndex(), result.getValue()); return null; diff --git a/src/main/java/org/apache/sling/models/impl/model/ConstructorParameter.java b/src/main/java/org/apache/sling/models/impl/model/ConstructorParameter.java index 2eb525cd..5700373e 100644 --- a/src/main/java/org/apache/sling/models/impl/model/ConstructorParameter.java +++ b/src/main/java/org/apache/sling/models/impl/model/ConstructorParameter.java @@ -20,10 +20,12 @@ import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Parameter; import java.lang.reflect.Type; import java.util.Arrays; import org.apache.sling.models.annotations.DefaultInjectionStrategy; +import org.apache.sling.models.impl.ReflectionUtil; import org.apache.sling.models.spi.injectorspecific.StaticInjectAnnotationProcessorFactory; /** @@ -34,23 +36,30 @@ public class ConstructorParameter extends AbstractInjectableElement { private final Type parameterType; - private final Type genericType; private final boolean isPrimitive; private final int parameterIndex; + /** + * Try to extract parameter names according to https://openjdk.org/jeps/118 (requires javac flag -parameters) + * @param parameter + * @param parameterIndex + * @param processorFactories + * @param defaultInjectionStrategy + */ + public static ConstructorParameter of(Parameter parameter, int parameterIndex, StaticInjectAnnotationProcessorFactory[] processorFactories, DefaultInjectionStrategy defaultInjectionStrategy) { + Type genericType = ReflectionUtil.mapPrimitiveClasses(parameter.getParameterizedType()); + boolean isPrimitive = (parameter.getParameterizedType() != genericType); + return new ConstructorParameter(parameter.getAnnotations(), parameter.getType(), genericType, isPrimitive, parameterIndex, parameter.getName(), processorFactories, defaultInjectionStrategy); + } + public ConstructorParameter(Annotation[] annotations, Type parameterType, Type genericType, boolean isPrimitive, - int parameterIndex, StaticInjectAnnotationProcessorFactory[] processorFactories, DefaultInjectionStrategy defaultInjectionStrategy) { - super(new FakeAnnotatedElement(annotations, parameterIndex), genericType, null, processorFactories, defaultInjectionStrategy); + int parameterIndex, String name, StaticInjectAnnotationProcessorFactory[] processorFactories, DefaultInjectionStrategy defaultInjectionStrategy) { + super(new FakeAnnotatedElement(annotations, parameterIndex), genericType, name, processorFactories, defaultInjectionStrategy); this.parameterType = parameterType; - this.genericType = genericType; this.isPrimitive = isPrimitive; this.parameterIndex = parameterIndex; } - public Type getGenericType() { - return this.genericType; - } - public Type getParameterType() { return this.parameterType; } @@ -65,7 +74,7 @@ public int getParameterIndex() { @Override public String toString() { - return "Parameter" + this.parameterIndex + "[" + this.genericType.toString() + "]"; + return "Parameter" + this.parameterIndex + "[" + getType().toString() + "]"; } public static class FakeAnnotatedElement implements AnnotatedElement { diff --git a/src/main/java/org/apache/sling/models/impl/model/ModelClassConstructor.java b/src/main/java/org/apache/sling/models/impl/model/ModelClassConstructor.java index 23460bec..b70ae781 100644 --- a/src/main/java/org/apache/sling/models/impl/model/ModelClassConstructor.java +++ b/src/main/java/org/apache/sling/models/impl/model/ModelClassConstructor.java @@ -20,12 +20,12 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Type; +import java.lang.reflect.Parameter; +import java.util.stream.IntStream; import javax.inject.Inject; import org.apache.sling.models.annotations.DefaultInjectionStrategy; -import org.apache.sling.models.impl.ReflectionUtil; import org.apache.sling.models.spi.injectorspecific.StaticInjectAnnotationProcessorFactory; public class ModelClassConstructor { @@ -38,16 +38,11 @@ public ModelClassConstructor(Constructor constructor, StaticInjectAnnotationP this.constructor = constructor; this.hasInjectAnnotation = constructor.isAnnotationPresent(Inject.class); - Type[] parameterTypes = constructor.getGenericParameterTypes(); - this.constructorParametersArray = new ConstructorParameter[parameterTypes.length]; - - for (int i = 0; i < parameterTypes.length; i++) { - Type genericType = ReflectionUtil.mapPrimitiveClasses(parameterTypes[i]); - boolean isPrimitive = (parameterTypes[i] != genericType); - this.constructorParametersArray[i] = new ConstructorParameter( - constructor.getParameterAnnotations()[i], constructor.getParameterTypes()[i], genericType, isPrimitive, i, - processorFactories, defaultInjectionStrategy); - } + Parameter[] parameters = constructor.getParameters(); + this.constructorParametersArray = IntStream + .range(0, parameters.length) + .mapToObj(i -> ConstructorParameter.of(parameters[i], i, processorFactories, defaultInjectionStrategy)) + .toArray(ConstructorParameter[]::new); } /** diff --git a/src/test/java/org/apache/sling/models/impl/injectors/SelfInjectorTest.java b/src/test/java/org/apache/sling/models/impl/injectors/SelfInjectorTest.java index 02a790de..4810625b 100644 --- a/src/test/java/org/apache/sling/models/impl/injectors/SelfInjectorTest.java +++ b/src/test/java/org/apache/sling/models/impl/injectors/SelfInjectorTest.java @@ -65,9 +65,9 @@ public class SelfInjectorTest { @Before public void setup() { lenient().when(modelAnnotation.defaultInjectionStrategy()).thenReturn(DefaultInjectionStrategy.REQUIRED); - firstConstructorParameter = new ConstructorParameter(new Annotation[0], Object.class, Object.class, true, 0, + firstConstructorParameter = new ConstructorParameter(new Annotation[0], Object.class, Object.class, true, 0, null, new StaticInjectAnnotationProcessorFactory[0], null); - secondConstructorParameter = new ConstructorParameter(new Annotation[0], Object.class, Object.class, true, 1, + secondConstructorParameter = new ConstructorParameter(new Annotation[0], Object.class, Object.class, true, 1, null, new StaticInjectAnnotationProcessorFactory[0], null); }