11package io .quarkus .amazon .lambda .deployment ;
22
33import java .lang .reflect .Method ;
4- import java .lang .reflect .Modifier ;
54import java .util .ArrayList ;
6- import java .util .Collections ;
75import java .util .HashMap ;
86import java .util .List ;
97import java .util .Map ;
1614import org .jboss .jandex .AnnotationInstance ;
1715import org .jboss .jandex .ClassInfo ;
1816import org .jboss .jandex .DotName ;
19- import org .jboss .jandex .MethodInfo ;
2017import org .jboss .logging .Logger ;
2118import org .joda .time .DateTime ;
2219
4643import io .quarkus .deployment .builditem .ShutdownContextBuildItem ;
4744import io .quarkus .deployment .builditem .nativeimage .ReflectiveClassBuildItem ;
4845import io .quarkus .deployment .builditem .nativeimage .ReflectiveHierarchyBuildItem ;
46+ import io .quarkus .deployment .builditem .nativeimage .ReflectiveMethodBuildItem ;
4947import io .quarkus .deployment .pkg .steps .NativeBuild ;
5048import io .quarkus .deployment .recording .RecorderContext ;
5149import io .quarkus .runtime .LaunchMode ;
@@ -90,88 +88,51 @@ List<AmazonLambdaBuildItem> discover(CombinedIndexBuildItem combinedIndexBuildIt
9088 BuildProducer <ReflectiveHierarchyBuildItem > reflectiveHierarchy ,
9189 BuildProducer <ReflectiveClassBuildItem > reflectiveClassBuildItemBuildProducer ) throws BuildException {
9290
93- List <ClassInfo > allKnownImplementors = new ArrayList <>(
94- combinedIndexBuildItem .getIndex ().getAllKnownImplementors (REQUEST_HANDLER )
91+ List <ClassInfo > requestHandlers = new ArrayList <>(
92+ combinedIndexBuildItem .getIndex ().getAllKnownImplementations (REQUEST_HANDLER )
9593 .stream ().filter (INCLUDE_HANDLER_PREDICATE ).toList ());
96- allKnownImplementors .addAll (combinedIndexBuildItem .getIndex ()
97- .getAllKnownImplementors (REQUEST_STREAM_HANDLER ).stream ().filter (INCLUDE_HANDLER_PREDICATE ).toList ());
98- allKnownImplementors .addAll (combinedIndexBuildItem .getIndex ()
94+
95+ List <ClassInfo > streamHandlers = new ArrayList <>(combinedIndexBuildItem .getIndex ()
96+ .getAllKnownImplementations (REQUEST_STREAM_HANDLER ).stream ().filter (INCLUDE_HANDLER_PREDICATE ).toList ());
97+ streamHandlers .addAll (combinedIndexBuildItem .getIndex ()
9998 .getAllKnownSubclasses (SKILL_STREAM_HANDLER ).stream ().filter (INCLUDE_HANDLER_PREDICATE ).toList ());
10099
101- if (allKnownImplementors . size () > 0 && providedLambda .isPresent ()) {
100+ if ((! requestHandlers . isEmpty () || ! streamHandlers . isEmpty ()) && providedLambda .isPresent ()) {
102101 throw new BuildException (
103102 "Multiple handler classes. You have a custom handler class and the " + providedLambda .get ().getProvider ()
104103 + " extension. Please remove one of them from your deployment." ,
105- Collections . emptyList ());
104+ List . of ());
106105
107106 }
108- AdditionalBeanBuildItem .Builder builder = AdditionalBeanBuildItem .builder ().setUnremovable ();
109- List <AmazonLambdaBuildItem > ret = new ArrayList <>();
107+ AdditionalBeanBuildItem .Builder additionalBeansBuilder = AdditionalBeanBuildItem .builder ().setUnremovable ();
108+ List <AmazonLambdaBuildItem > amazonLambdas = new ArrayList <>();
110109
111- for (ClassInfo info : allKnownImplementors ) {
112- if (Modifier .isAbstract (info . flags () )) {
110+ for (ClassInfo requestHandler : requestHandlers ) {
111+ if (requestHandler .isAbstract ()) {
113112 continue ;
114113 }
115114
116- final DotName name = info . name ();
117- final String lambda = name .toString ();
118- builder . addBeanClass ( lambda );
115+ additionalBeansBuilder . addBeanClass ( requestHandler . name (). toString () );
116+ amazonLambdas . add ( new AmazonLambdaBuildItem ( requestHandler . name () .toString (), getCdiName ( requestHandler ), false ) );
117+ }
119118
120- String cdiName = null ;
121- AnnotationInstance named = info .declaredAnnotation (NAMED );
122- if (named != null ) {
123- cdiName = named .value ().asString ();
119+ for (ClassInfo streamHandler : streamHandlers ) {
120+ if (streamHandler .isAbstract ()) {
121+ continue ;
124122 }
125123
126- ClassInfo current = info ;
127- boolean done = false ;
128- boolean streamHandler = info .superName ().equals (SKILL_STREAM_HANDLER );
129- while (current != null && !done ) {
130- for (MethodInfo method : current .methods ()) {
131- if (method .name ().equals ("handleRequest" )) {
132- if (method .parametersCount () == 3 ) {
133- streamHandler = true ;
134- done = true ;
135- break ;
136- } else if (method .parametersCount () == 2
137- && !method .parameterType (0 ).name ().equals (DotName .createSimple (Object .class .getName ()))) {
138- String source = getClass ().getSimpleName () + " > " + method .declaringClass () + "[" + method + "]" ;
139-
140- reflectiveHierarchy .produce (ReflectiveHierarchyBuildItem
141- .builder (method .parameterType (0 ))
142- .source (source )
143- .build ());
144- reflectiveHierarchy .produce (ReflectiveHierarchyBuildItem
145- .builder (method .returnType ())
146- .source (source )
147- .build ());
148- done = true ;
149- break ;
150- }
151- }
152- }
153- if (!done ) {
154- current = combinedIndexBuildItem .getIndex ().getClassByName (current .superName ());
155- }
156- }
157- if (done ) {
158- String handlerClass = current .name ().toString ();
159- ret .add (new AmazonLambdaBuildItem (handlerClass , cdiName , streamHandler ));
160- reflectiveClassBuildItemBuildProducer .produce (ReflectiveClassBuildItem .builder (handlerClass ).methods ()
161- .reason (getClass ().getName ()
162- + ": reflectively accessed in io.quarkus.amazon.lambda.runtime.AmazonLambdaRecorder.discoverHandlerMethod" )
163- .build ());
164- } else {
165- // Fall back to the root implementor if a matching `handleRequest` is not found in the class hierarchy
166- ret .add (new AmazonLambdaBuildItem (lambda , cdiName , streamHandler ));
167- }
124+ additionalBeansBuilder .addBeanClass (streamHandler .name ().toString ());
125+ amazonLambdas .add (new AmazonLambdaBuildItem (streamHandler .name ().toString (), getCdiName (streamHandler ), true ));
168126 }
169- additionalBeanBuildItemBuildProducer .produce (builder .build ());
127+
128+ additionalBeanBuildItemBuildProducer .produce (additionalBeansBuilder .build ());
129+
170130 reflectiveClassBuildItemBuildProducer
171131 .produce (ReflectiveClassBuildItem .builder (FunctionError .class ).methods ().fields ()
172132 .reason (getClass ().getName ())
173133 .build ());
174- return ret ;
134+
135+ return amazonLambdas ;
175136 }
176137
177138 @ BuildStep
@@ -225,7 +186,9 @@ public void recordStaticInitHandlerClass(CombinedIndexBuildItem index,
225186 LambdaObjectMapperInitializedBuildItem mapper , // ordering!
226187 Optional <ProvidedAmazonLambdaHandlerBuildItem > providedLambda ,
227188 AmazonLambdaStaticRecorder recorder ,
228- RecorderContext context ) {
189+ RecorderContext context ,
190+ BuildProducer <ReflectiveMethodBuildItem > reflectiveMethods ,
191+ BuildProducer <ReflectiveHierarchyBuildItem > reflectiveHierarchies ) {
229192 // can set handler within static initialization if only one handler exists in deployment
230193 if (providedLambda .isPresent ()) {
231194 boolean useStreamHandler = false ;
@@ -243,6 +206,7 @@ public void recordStaticInitHandlerClass(CombinedIndexBuildItem index,
243206 } else {
244207 RequestHandlerJandexDefinition requestHandlerJandexDefinition = RequestHandlerJandexUtil
245208 .discoverHandlerMethod (providedLambda .get ().getHandlerClass ().getName (), index .getComputingIndex ());
209+ registerForReflection (requestHandlerJandexDefinition , reflectiveMethods , reflectiveHierarchies );
246210 recorder .setHandlerClass (toRequestHandlerDefinition (requestHandlerJandexDefinition , context ));
247211 }
248212 } else if (lambdas != null && lambdas .size () == 1 ) {
@@ -255,6 +219,7 @@ public void recordStaticInitHandlerClass(CombinedIndexBuildItem index,
255219 } else {
256220 RequestHandlerJandexDefinition requestHandlerJandexDefinition = RequestHandlerJandexUtil
257221 .discoverHandlerMethod (item .getHandlerClass (), index .getComputingIndex ());
222+ registerForReflection (requestHandlerJandexDefinition , reflectiveMethods , reflectiveHierarchies );
258223 recorder .setHandlerClass (toRequestHandlerDefinition (requestHandlerJandexDefinition , context ));
259224 }
260225 } else if (lambdas == null || lambdas .isEmpty ()) {
@@ -282,7 +247,9 @@ public void recordHandlerClass(CombinedIndexBuildItem index,
282247 BeanContainerBuildItem beanContainerBuildItem ,
283248 AmazonLambdaRecorder recorder ,
284249 List <ServiceStartBuildItem > orderServicesFirst , // try to order this after service recorders
285- RecorderContext context ) {
250+ RecorderContext context ,
251+ BuildProducer <ReflectiveMethodBuildItem > reflectiveMethods ,
252+ BuildProducer <ReflectiveHierarchyBuildItem > reflectiveHierarchies ) {
286253 // Have to set lambda class at runtime if there is not a provided lambda or there is more than one lambda in
287254 // deployment
288255 if (!providedLambda .isPresent () && lambdas != null && lambdas .size () > 1 ) {
@@ -305,10 +272,12 @@ public void recordHandlerClass(CombinedIndexBuildItem index,
305272 if (i .getName () == null ) {
306273 RequestHandlerJandexDefinition requestHandlerJandexDefinition = RequestHandlerJandexUtil
307274 .discoverHandlerMethod (i .getHandlerClass (), index .getComputingIndex ());
275+ registerForReflection (requestHandlerJandexDefinition , reflectiveMethods , reflectiveHierarchies );
308276 unnamed .add (toRequestHandlerDefinition (requestHandlerJandexDefinition , context ));
309277 } else {
310278 RequestHandlerJandexDefinition requestHandlerJandexDefinition = RequestHandlerJandexUtil
311279 .discoverHandlerMethod (i .getHandlerClass (), index .getComputingIndex ());
280+ registerForReflection (requestHandlerJandexDefinition , reflectiveMethods , reflectiveHierarchies );
312281 named .put (i .getName (), toRequestHandlerDefinition (requestHandlerJandexDefinition , context ));
313282 }
314283 }
@@ -357,7 +326,40 @@ void recordExpectedExceptions(LambdaBuildTimeConfig config,
357326 recorder .setExpectedExceptionClasses (classes );
358327 }
359328
360- public RequestHandlerDefinition toRequestHandlerDefinition (RequestHandlerJandexDefinition jandexDefinition ,
329+ private static String getCdiName (ClassInfo handler ) {
330+ AnnotationInstance named = handler .declaredAnnotation (NAMED );
331+ if (named == null ) {
332+ return null ;
333+ }
334+ return named .value ().asString ();
335+ }
336+
337+ private static void registerForReflection (RequestHandlerJandexDefinition requestHandlerJandexDefinition ,
338+ BuildProducer <ReflectiveMethodBuildItem > reflectiveMethods ,
339+ BuildProducer <ReflectiveHierarchyBuildItem > reflectiveHierarchies ) {
340+ String source = AmazonLambdaProcessor .class .getSimpleName () + " > "
341+ + requestHandlerJandexDefinition .method ().declaringClass () + "[" + requestHandlerJandexDefinition .method ()
342+ + "]" ;
343+ reflectiveHierarchies .produce (ReflectiveHierarchyBuildItem
344+ .builder (requestHandlerJandexDefinition .inputOutputTypes ().inputType ())
345+ .source (source )
346+ .build ());
347+ reflectiveHierarchies .produce (ReflectiveHierarchyBuildItem
348+ .builder (requestHandlerJandexDefinition .inputOutputTypes ().outputType ())
349+ .source (source )
350+ .build ());
351+ if (requestHandlerJandexDefinition .inputOutputTypes ().isCollection ()) {
352+ reflectiveMethods .produce (new ReflectiveMethodBuildItem (
353+ "method reflectively accessed in io.quarkus.amazon.lambda.runtime.AmazonLambdaRecorder.discoverHandlerMethod" ,
354+ requestHandlerJandexDefinition .method ()));
355+ reflectiveHierarchies .produce (ReflectiveHierarchyBuildItem
356+ .builder (requestHandlerJandexDefinition .inputOutputTypes ().elementType ())
357+ .source (source )
358+ .build ());
359+ }
360+ }
361+
362+ private static RequestHandlerDefinition toRequestHandlerDefinition (RequestHandlerJandexDefinition jandexDefinition ,
361363 RecorderContext context ) {
362364 return new RequestHandlerDefinition (
363365 (Class <? extends RequestHandler <?, ?>>) context .classProxy (jandexDefinition .handlerClass ().name ().toString ()),
0 commit comments