1616import java .util .Arrays ;
1717import java .util .List ;
1818
19+ import org .eclipse .jdt .core .dom .ASTNode ;
1920import org .eclipse .jdt .core .dom .ASTVisitor ;
2021import org .eclipse .jdt .core .dom .CompilationUnit ;
2122import org .eclipse .jdt .core .dom .Expression ;
2223import org .eclipse .jdt .core .dom .IAnnotationBinding ;
24+ import org .eclipse .jdt .core .dom .IMethodBinding ;
2325import org .eclipse .jdt .core .dom .ITypeBinding ;
2426import org .eclipse .jdt .core .dom .MemberValuePair ;
27+ import org .eclipse .jdt .core .dom .MethodDeclaration ;
28+ import org .eclipse .jdt .core .dom .MethodInvocation ;
2529import org .eclipse .jdt .core .dom .NormalAnnotation ;
2630import org .eclipse .jdt .core .dom .TypeDeclaration ;
2731import org .springframework .ide .vscode .boot .index .SpringMetamodelIndex ;
3034import org .springframework .ide .vscode .boot .java .annotations .AnnotationHierarchies ;
3135import org .springframework .ide .vscode .boot .java .requestmapping .WebConfigIndexElement ;
3236import org .springframework .ide .vscode .boot .java .requestmapping .WebConfigJavaIndexer ;
37+ import org .springframework .ide .vscode .boot .java .requestmapping .WebfluxUtils ;
3338import org .springframework .ide .vscode .boot .java .utils .ASTUtils ;
3439import org .springframework .ide .vscode .commons .java .IJavaProject ;
3540import org .springframework .ide .vscode .commons .languageserver .reconcile .ProblemType ;
@@ -93,23 +98,77 @@ public boolean visit(NormalAnnotation annotation) {
9398
9499 Expression valueExpression = pair .getValue ();
95100 String versionValue = ASTUtils .getExpressionValueAsString (valueExpression , (d ) -> {});
96- versionValue = updateVersion (versionValue );
97101
98- SemanticApiVersionParser parser = new SemanticApiVersionParser ();
99- try {
100- parser .parseVersion (versionValue );
101- }
102- catch (IllegalStateException e ) {
103- ReconcileProblemImpl problem = new ReconcileProblemImpl (getProblemType (), PROBLEM_LABEL ,
104- valueExpression .getStartPosition (), valueExpression .getLength ());
105-
106- context .getProblemCollector ().accept (problem );
107- }
102+ validateVersion (context , valueExpression , versionValue );
108103 }
109104 );
110105
111106 return super .visit (annotation );
112107 }
108+
109+ @ Override
110+ public boolean visit (MethodDeclaration method ) {
111+ boolean isWebfluxRouter = WebfluxUtils .isFunctionalWebRouterBean (method );
112+ if (isWebfluxRouter ) {
113+ if (!context .isCompleteAst ()) {
114+ throw new RequiredCompleteAstException ();
115+ }
116+ }
117+
118+ return super .visit (method );
119+ }
120+
121+ /**
122+ * this is the piece of the reconciler that validates version in functional endpoint definitions
123+ */
124+ @ Override
125+ public boolean visit (MethodInvocation methodInvocation ) {
126+ IMethodBinding methodBinding = methodInvocation .resolveMethodBinding ();
127+ if (methodBinding == null ) return super .visit (methodInvocation );
128+
129+ // Check if this is a call to RequestPredicates.version() method
130+ String methodName = methodBinding .getName ();
131+ if (!"version" .equals (methodName )) {
132+ return super .visit (methodInvocation );
133+ }
134+
135+ // Check if the declaring class is RequestPredicates (for both WebMVC and WebFlux)
136+ ITypeBinding declaringClass = methodBinding .getDeclaringClass ();
137+ if (declaringClass == null ) {
138+ return super .visit (methodInvocation );
139+ }
140+
141+ String declaringClassName = declaringClass .getQualifiedName ();
142+ boolean isWebMvcVersion = WebfluxUtils .MVC_REQUEST_PREDICATES_TYPE .equals (declaringClassName );
143+ boolean isWebFluxVersion = WebfluxUtils .REQUEST_PREDICATES_TYPE .equals (declaringClassName );
144+
145+ if (!isWebMvcVersion && !isWebFluxVersion ) {
146+ return super .visit (methodInvocation );
147+ }
148+
149+ // Extract the version argument
150+ @ SuppressWarnings ("unchecked" )
151+ List <Expression > arguments = methodInvocation .arguments ();
152+ if (arguments == null || arguments .isEmpty () || arguments .size () > 1 ) {
153+ return super .visit (methodInvocation );
154+ }
155+
156+ if (!context .isIndexComplete ()) {
157+ throw new RequiredCompleteIndexException ();
158+ }
159+
160+ if (!isApiVersioningConfiguredWithStanardVersionParser (project )) {
161+ return super .visit (methodInvocation );
162+ }
163+
164+ Expression expression = arguments .get (0 );
165+ String versionValue = ASTUtils .getExpressionValueAsString (expression , (d ) -> {});
166+
167+ // Validate the version
168+ validateVersion (context , expression , versionValue );
169+
170+ return super .visit (methodInvocation );
171+ }
113172
114173 /**
115174 * this is the piece of the reconciler that looks for changes to web configs and then marks all the potentially affected
@@ -136,6 +195,21 @@ private String updateVersion(String version) {
136195 return (baselineVersion ? version .substring (0 , version .length () - 1 ) : version );
137196 }
138197
198+ private void validateVersion (ReconcilingContext context , ASTNode valueExpression , String versionValue ) {
199+ versionValue = updateVersion (versionValue );
200+
201+ SemanticApiVersionParser parser = new SemanticApiVersionParser ();
202+ try {
203+ parser .parseVersion (versionValue );
204+ }
205+ catch (IllegalStateException e ) {
206+ ReconcileProblemImpl problem = new ReconcileProblemImpl (getProblemType (), PROBLEM_LABEL ,
207+ valueExpression .getStartPosition (), valueExpression .getLength ());
208+
209+ context .getProblemCollector ().accept (problem );
210+ }
211+ }
212+
139213 private boolean isApiVersioningConfiguredWithStanardVersionParser (IJavaProject project ) {
140214 List <WebConfigIndexElement > webConfigs = springIndex .getNodesOfType (project .getElementName (), WebConfigIndexElement .class );
141215 for (WebConfigIndexElement webConfig : webConfigs ) {
0 commit comments