11package io .quarkiverse .openapi .generator .deployment .template ;
22
33import java .io .File ;
4+ import java .lang .reflect .Method ;
45import java .nio .file .Path ;
6+ import java .util .ArrayList ;
7+ import java .util .Collections ;
58import java .util .HashMap ;
9+ import java .util .LinkedHashMap ;
10+ import java .util .List ;
611import java .util .concurrent .CompletableFuture ;
712import java .util .concurrent .CompletionStage ;
813import java .util .concurrent .ExecutionException ;
14+ import java .util .stream .Collectors ;
915
16+ import org .openapitools .codegen .CodegenSecurity ;
1017import org .openapitools .codegen .model .OperationMap ;
1118
1219import io .quarkiverse .openapi .generator .deployment .codegen .OpenApiGeneratorOutputPaths ;
@@ -32,6 +39,7 @@ private OpenApiNamespaceResolver() {
3239 * @param codegenConfig Map with the model codegen properties
3340 * @return true if the given model class should generate the deprecated attributes
3441 */
42+ @ SuppressWarnings ("unused" )
3543 public boolean genDeprecatedModelAttr (final String pkg , final String classname ,
3644 final HashMap <String , Object > codegenConfig ) {
3745 final String key = String .format ("%s.%s.%s" , pkg , classname , GENERATE_DEPRECATED_PROP );
@@ -44,38 +52,92 @@ public boolean genDeprecatedModelAttr(final String pkg, final String classname,
4452 * @param codegenConfig Map with the model codegen properties
4553 * @return true if the given model class should generate the deprecated attributes
4654 */
55+ @ SuppressWarnings ("unused" )
4756 public boolean genDeprecatedApiAttr (final String pkg , final String classname ,
4857 final HashMap <String , Object > codegenConfig ) {
4958 final String key = String .format ("%s.%s.%s" , pkg , classname , GENERATE_DEPRECATED_PROP );
5059 return Boolean .parseBoolean (codegenConfig .getOrDefault (key , "true" ).toString ());
5160 }
5261
62+ @ SuppressWarnings ("unused" )
5363 public String parseUri (String uri ) {
5464 return OpenApiGeneratorOutputPaths .getRelativePath (Path .of (uri )).toString ().replace (File .separatorChar , '/' );
5565 }
5666
67+ @ SuppressWarnings ("unused" )
5768 public boolean hasAuthMethods (OperationMap operations ) {
5869 return operations != null && operations .getOperation ().stream ().anyMatch (operation -> operation .hasAuthMethods );
5970 }
6071
72+ /**
73+ * Ignore the OAuth flows by filtering every oauth instance by name. The inner openapi-generator library duplicates the
74+ * OAuth instances per flow in the openapi spec.
75+ * So a specification file with more than one flow defined has two entries in the list. For now, we do not use this
76+ * information in runtime so it can be safely filtered and ignored.
77+ *
78+ * @param oauthOperations passed through the Qute template
79+ * @see "resources/templates/libraries/microprofile/auth/compositeAuthenticationProvider.qute"
80+ * @return The list filtered by unique auth name
81+ */
82+ @ SuppressWarnings ("unused" )
83+ public List <CodegenSecurity > getUniqueOAuthOperations (List <CodegenSecurity > oauthOperations ) {
84+ if (oauthOperations != null ) {
85+ return new ArrayList <>(oauthOperations .stream ()
86+ .collect (Collectors .toMap (security -> security .name , security -> security ,
87+ (existing , replacement ) -> existing , LinkedHashMap ::new ))
88+ .values ());
89+ }
90+ return Collections .emptyList ();
91+ }
92+
6193 @ Override
6294 public CompletionStage <Object > resolve (EvalContext context ) {
6395 try {
64- Class <?>[] classArgs = new Class [context .getParams ().size ()];
6596 Object [] args = new Object [context .getParams ().size ()];
97+ Class <?>[] classArgs = new Class [context .getParams ().size ()];
98+
6699 int i = 0 ;
67100 for (Expression expr : context .getParams ()) {
68101 args [i ] = context .evaluate (expr ).toCompletableFuture ().get ();
69102 classArgs [i ] = args [i ].getClass ();
70103 i ++;
71104 }
72- return CompletableFuture
73- .completedFuture (this .getClass ().getMethod (context .getName (), classArgs ).invoke (this , args ));
105+
106+ Method targetMethod = findCompatibleMethod (context .getName (), classArgs );
107+ if (targetMethod == null ) {
108+ throw new NoSuchMethodException ("No compatible method found for: " + context .getName ());
109+ }
110+
111+ return CompletableFuture .completedFuture (targetMethod .invoke (this , args ));
74112 } catch (ReflectiveOperationException | InterruptedException | ExecutionException ex ) {
75113 return CompletableFuture .failedStage (ex );
76114 }
77115 }
78116
117+ private Method findCompatibleMethod (String methodName , Class <?>[] argTypes ) {
118+ for (Method method : this .getClass ().getMethods ()) {
119+ if (method .getName ().equals (methodName )) {
120+ Class <?>[] paramTypes = method .getParameterTypes ();
121+ if (isAssignable (paramTypes , argTypes )) {
122+ return method ;
123+ }
124+ }
125+ }
126+ return null ;
127+ }
128+
129+ private boolean isAssignable (Class <?>[] paramTypes , Class <?>[] argTypes ) {
130+ if (paramTypes .length != argTypes .length ) {
131+ return false ;
132+ }
133+ for (int i = 0 ; i < paramTypes .length ; i ++) {
134+ if (!paramTypes [i ].isAssignableFrom (argTypes [i ])) {
135+ return false ;
136+ }
137+ }
138+ return true ;
139+ }
140+
79141 @ Override
80142 public String getNamespace () {
81143 return "openapi" ;
0 commit comments