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)
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 9724013..02d0541 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 setConstructorParameter(ConstructorParameter constructorParameter, List<Object> parameterValues, Object value) {
         if (constructorParameter.getParameterType() instanceof Class<?>) {
-            Result<Object> result = adaptIfNecessary(value, (Class<?>) constructorParameter.getParameterType(), constructorParameter.getGenericType());
+            Result<Object> 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 2eb525c..5700373 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,21 +36,28 @@
 public class ConstructorParameter extends AbstractInjectableElement {
 
     private final Type parameterType;
-    private final Type genericType;
     private final boolean isPrimitive;
     private final int parameterIndex;
 
-    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);
-        this.parameterType = parameterType;
-        this.genericType = genericType;
-        this.isPrimitive = isPrimitive;
-        this.parameterIndex = 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 Type getGenericType() {
-        return this.genericType;
+    public ConstructorParameter(Annotation[] annotations, Type parameterType, Type genericType, boolean isPrimitive,
+            int parameterIndex, String name, StaticInjectAnnotationProcessorFactory[] processorFactories, DefaultInjectionStrategy defaultInjectionStrategy) {
+        super(new FakeAnnotatedElement(annotations, parameterIndex), genericType, name, processorFactories, defaultInjectionStrategy);
+        this.parameterType = parameterType;
+        this.isPrimitive = isPrimitive;
+        this.parameterIndex = parameterIndex;
     }
 
     public Type getParameterType() {
@@ -65,7 +74,7 @@
 
     @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 23460be..b70ae78 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<M> {
@@ -38,16 +38,11 @@
         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 02a790d..4810625 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 @@
     @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);
     }