18
18
import lombok .extern .slf4j .Slf4j ;
19
19
import org .jetbrains .annotations .NotNull ;
20
20
import org .openrewrite .ExecutionContext ;
21
+ import org .openrewrite .FileAttributes ;
21
22
import org .openrewrite .Parser ;
22
23
import org .openrewrite .SourceFile ;
23
24
import org .openrewrite .internal .lang .Nullable ;
24
25
import org .openrewrite .java .JavaParser ;
25
26
import org .openrewrite .java .internal .JavaTypeCache ;
26
27
import org .openrewrite .java .marker .JavaSourceSet ;
28
+ import org .openrewrite .java .tree .J ;
29
+ import org .openrewrite .java .tree .JavaType ;
27
30
import org .openrewrite .marker .Generated ;
28
31
import org .openrewrite .marker .Marker ;
29
32
import org .openrewrite .marker .Markers ;
30
33
import org .openrewrite .xml .tree .Xml ;
31
34
import org .springframework .core .io .Resource ;
32
35
import org .springframework .sbm .utils .ResourceUtil ;
33
36
37
+ import java .io .InputStream ;
38
+ import java .nio .file .Files ;
34
39
import java .nio .file .Path ;
35
40
import java .nio .file .Paths ;
36
- import java .util .ArrayList ;
37
- import java .util .Collection ;
38
- import java .util .List ;
39
- import java .util .Set ;
41
+ import java .util .*;
40
42
import java .util .function .Predicate ;
43
+ import java .util .function .Supplier ;
41
44
import java .util .function .UnaryOperator ;
42
45
import java .util .stream .Collectors ;
43
46
import java .util .stream .Stream ;
@@ -73,7 +76,7 @@ public <T extends SourceFile> UnaryOperator<T> addProvenance(
73
76
/**
74
77
* Parse Java sources and resources under {@code src/main} of current module.
75
78
*/
76
- public List < SourceFile > processMainSources (
79
+ public SourceSetParsingResult processMainSources (
77
80
Path baseDir ,
78
81
List <Resource > resources ,
79
82
Xml .Document moduleBuildFile ,
@@ -116,20 +119,40 @@ public List<SourceFile> processMainSources(
116
119
javaParserBuilder .typeCache (typeCache );
117
120
118
121
Iterable <Parser .Input > inputs = mainJavaSources .stream ()
119
- .map (r -> new Parser .Input (ResourceUtil .getPath (r ), () -> ResourceUtil .getInputStream (r )))
122
+ .map (r -> {
123
+ FileAttributes fileAttributes = null ;
124
+ Path path = ResourceUtil .getPath (r );
125
+ boolean isSynthetic = Files .exists (path );
126
+ Supplier <InputStream > inputStreamSupplier = () -> ResourceUtil .getInputStream (r );
127
+ Parser .Input input = new Parser .Input (path , fileAttributes , inputStreamSupplier , isSynthetic );
128
+ return input ;
129
+ })
120
130
.toList ();
121
131
122
- Stream <? extends SourceFile > cus = Stream .of (javaParserBuilder )
123
- .map (JavaParser .Builder ::build )
124
- .flatMap (parser -> parser .parseInputs (inputs , baseDir , executionContext ))
125
- .peek (s -> alreadyParsed .add (baseDir .resolve (s .getSourcePath ())));
132
+ Set <JavaType .FullyQualified > localClassesCp = new HashSet <>();
133
+ JavaSourceSet javaSourceSet = sourceSet ("main" , dependencies , typeCache );
134
+ List <? extends SourceFile > cus = javaParserBuilder .build ()
135
+ .parseInputs (inputs , baseDir , executionContext )
136
+ .peek (s -> {
137
+ ((J .CompilationUnit )s ).getClasses ()
138
+ .stream ()
139
+ .map (J .ClassDeclaration ::getType )
140
+ .forEach (localClassesCp ::add );
141
+
142
+ alreadyParsed .add (baseDir .resolve (s .getSourcePath ()));
143
+ })
144
+ .toList ();
126
145
146
+ // TODO: This is a hack:
147
+ // Parsed java sources are not themselves on the classpath (here).
148
+ // The actual parsing happens when the stream is terminated (toList),
149
+ // therefore the toList() must be called before the parsed compilation units can be added to the classpath
127
150
List <Marker > mainProjectProvenance = new ArrayList <>(provenanceMarkers );
128
- mainProjectProvenance .add (sourceSet ("main" , dependencies , typeCache ));
151
+ javaSourceSet = appendToClasspath (localClassesCp , javaSourceSet );
152
+ mainProjectProvenance .add (javaSourceSet );
129
153
130
- // FIXME: 945 Why target and not all main?
131
154
List <Path > parsedJavaPaths = javaSourcesInTarget .stream ().map (ResourceUtil ::getPath ).toList ();
132
- Stream <SourceFile > parsedJava = cus .map (addProvenance (baseDir , mainProjectProvenance , parsedJavaPaths ));
155
+ Stream <SourceFile > parsedJava = cus .stream (). map (addProvenance (baseDir , mainProjectProvenance , parsedJavaPaths ));
133
156
log .debug ("[%s] Scanned %d java source files in main scope." .formatted (currentProject , mainJavaSources .size ()));
134
157
135
158
//Filter out any generated source files from the returned list, as we do not want to apply the recipe to the
@@ -148,7 +171,22 @@ public List<SourceFile> processMainSources(
148
171
log .debug ("[%s] Scanned %d resource files in main scope." .formatted (currentProject , (alreadyParsed .size () - sourcesParsedBefore )));
149
172
// Any resources parsed from "main/resources" should also have the main source set added to them.
150
173
sourceFiles .addAll (parsedResourceFiles );
151
- return sourceFiles ;
174
+ return new SourceSetParsingResult (sourceFiles , javaSourceSet .getClasspath ());
175
+ }
176
+
177
+ /**
178
+ * Add entries that don't exist in the classpath of {@code javaSourceSet} from {@code appendingClasspath}.
179
+ */
180
+ @ NotNull
181
+ private static JavaSourceSet appendToClasspath (Set <JavaType .FullyQualified > appendingClasspath , JavaSourceSet javaSourceSet ) {
182
+ List <JavaType .FullyQualified > curCp = javaSourceSet .getClasspath ();
183
+ appendingClasspath .forEach (f -> {
184
+ if (!curCp .contains (f )) {
185
+ curCp .add (f );
186
+ }
187
+ });
188
+ javaSourceSet = javaSourceSet .withClasspath (new ArrayList <>(curCp ));
189
+ return javaSourceSet ;
152
190
}
153
191
154
192
@ NotNull
@@ -160,7 +198,7 @@ private static JavaSourceSet sourceSet(String name, List<Path> dependencies, Jav
160
198
/**
161
199
* Parse Java sources and resource files under {@code src/test}.
162
200
*/
163
- public List < SourceFile > processTestSources (
201
+ public SourceSetParsingResult processTestSources (
164
202
Path baseDir ,
165
203
Xml .Document moduleBuildFile ,
166
204
JavaParser .Builder <? extends JavaParser , ?> javaParserBuilder ,
@@ -169,8 +207,8 @@ public List<SourceFile> processTestSources(
169
207
Set <Path > alreadyParsed ,
170
208
ExecutionContext executionContext ,
171
209
MavenProject currentProject ,
172
- List <Resource > resources
173
- ) {
210
+ List <Resource > resources ,
211
+ List < JavaType . FullyQualified > classpath ) {
174
212
log .info ("Processing test sources in module '%s'" .formatted (currentProject .getProjectId ()));
175
213
176
214
List <Path > testDependencies = currentProject .getTestClasspathElements ();
@@ -186,14 +224,25 @@ public List<SourceFile> processTestSources(
186
224
.map (r -> new Parser .Input (ResourceUtil .getPath (r ), () -> ResourceUtil .getInputStream (r )))
187
225
.toList ();
188
226
189
- Stream <? extends SourceFile > cus = Stream .of (javaParserBuilder )
190
- .map (JavaParser .Builder ::build )
191
- .flatMap (parser -> parser .parseInputs (inputs , baseDir , executionContext ));
227
+ final List <JavaType .FullyQualified > localClassesCp = new ArrayList <>();
228
+ List <? extends SourceFile > cus = javaParserBuilder .build ()
229
+ .parseInputs (inputs , baseDir , executionContext )
230
+ .peek (s -> {
231
+ ((J .CompilationUnit ) s ).getClasses ()
232
+ .stream ()
233
+ .map (J .ClassDeclaration ::getType )
234
+ .forEach (localClassesCp ::add );
235
+ alreadyParsed .add (baseDir .resolve (s .getSourcePath ()));
236
+ })
237
+ .toList ();
192
238
193
239
List <Marker > markers = new ArrayList <>(provenanceMarkers );
194
- markers .add (sourceSet ("test" , testDependencies , typeCache ));
195
240
196
- Stream <SourceFile > parsedJava = cus .map (addProvenance (baseDir , markers , null ));
241
+ JavaSourceSet javaSourceSet = sourceSet ("test" , testDependencies , typeCache );
242
+ Set <JavaType .FullyQualified > curClasspath = Stream .concat (classpath .stream (), localClassesCp .stream ()).collect (Collectors .toSet ());
243
+ javaSourceSet = appendToClasspath (curClasspath , javaSourceSet );
244
+ markers .add (javaSourceSet );
245
+ Stream <SourceFile > parsedJava = cus .stream ().map (addProvenance (baseDir , markers , null ));
197
246
198
247
log .debug ("[%s] Scanned %d java source files in test scope." .formatted (currentProject , testJavaSources .size ()));
199
248
Stream <SourceFile > sourceFiles = parsedJava ;
@@ -205,7 +254,7 @@ public List<SourceFile> processTestSources(
205
254
log .debug ("[%s] Scanned %d resource files in test scope." .formatted (currentProject , (alreadyParsed .size () - sourcesParsedBefore )));
206
255
sourceFiles = Stream .concat (sourceFiles , parsedResourceFiles );
207
256
List <SourceFile > result = sourceFiles .toList ();
208
- return result ;
257
+ return new SourceSetParsingResult ( result , javaSourceSet . getClasspath ()) ;
209
258
}
210
259
211
260
0 commit comments