Skip to content

Commit 442b051

Browse files
authored
feat: use single scanner for plugin class scan (#21107)
Fixes #21016
1 parent 2ad796b commit 442b051

21 files changed

+196
-58
lines changed

flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinBuildFrontendTask.kt

+24-3
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@
1515
*/
1616
package com.vaadin.gradle
1717

18+
import com.vaadin.experimental.FeatureFlags
1819
import com.vaadin.flow.plugin.base.BuildFrontendUtil
1920
import com.vaadin.flow.server.Constants
2021
import com.vaadin.flow.server.frontend.BundleValidationUtil
2122
import com.vaadin.flow.server.frontend.FrontendUtils
2223
import com.vaadin.flow.server.frontend.TaskCleanFrontendFiles
24+
import com.vaadin.flow.server.frontend.scanner.ClassFinder
25+
import com.vaadin.flow.server.frontend.scanner.FrontendDependenciesScanner
26+
import com.vaadin.flow.server.frontend.scanner.FrontendDependenciesScanner.FrontendDependenciesScannerFactory
2327
import com.vaadin.pro.licensechecker.LicenseChecker
2428
import org.gradle.api.DefaultTask
2529
import org.gradle.api.provider.Property
@@ -80,9 +84,26 @@ public abstract class VaadinBuildFrontendTask : DefaultTask() {
8084
check(tokenFile.exists()) { "token file $tokenFile doesn't exist!" }
8185

8286
val cleanTask = TaskCleanFrontendFiles(config.npmFolder.get(),
83-
BuildFrontendUtil.getGeneratedFrontendDirectory(adapter.get()), adapter.get().classFinder
87+
BuildFrontendUtil.getGeneratedFrontendDirectory(adapter.get()), adapter.get().classFinder)
88+
89+
val reactEnabled: Boolean = adapter.get().isReactEnabled()
90+
&& FrontendUtils.isReactRouterRequired(
91+
BuildFrontendUtil.getFrontendDirectory(adapter.get())
92+
)
93+
val featureFlags: FeatureFlags = FeatureFlags(
94+
adapter.get().createLookup(adapter.get().getClassFinder())
8495
)
85-
BuildFrontendUtil.runNodeUpdater(adapter.get())
96+
if (adapter.get().javaResourceFolder() != null) {
97+
featureFlags.setPropertiesLocation(adapter.get().javaResourceFolder())
98+
}
99+
val frontendDependencies: FrontendDependenciesScanner = FrontendDependenciesScannerFactory()
100+
.createScanner(
101+
!adapter.get().optimizeBundle(), adapter.get().getClassFinder(),
102+
adapter.get().generateEmbeddableWebComponents(), featureFlags,
103+
reactEnabled
104+
)
105+
106+
BuildFrontendUtil.runNodeUpdater(adapter.get(), frontendDependencies)
86107

87108
if (adapter.get().generateBundle() && BundleValidationUtil.needsBundleBuild
88109
(adapter.get().servletResourceOutputDirectory())) {
@@ -92,7 +113,7 @@ public abstract class VaadinBuildFrontendTask : DefaultTask() {
92113
}
93114
}
94115
LicenseChecker.setStrictOffline(true)
95-
val licenseRequired = BuildFrontendUtil.validateLicenses(adapter.get())
116+
val licenseRequired = BuildFrontendUtil.validateLicenses(adapter.get(), frontendDependencies)
96117

97118
BuildFrontendUtil.updateBuildFile(adapter.get(), licenseRequired)
98119
}

flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/BuildFrontendMojo.java

+19-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.apache.maven.plugins.annotations.Parameter;
3131
import org.apache.maven.plugins.annotations.ResolutionScope;
3232

33+
import com.vaadin.experimental.FeatureFlags;
3334
import com.vaadin.flow.component.dependency.JavaScript;
3435
import com.vaadin.flow.component.dependency.JsModule;
3536
import com.vaadin.flow.component.dependency.NpmPackage;
@@ -41,6 +42,7 @@
4142
import com.vaadin.flow.server.frontend.BundleValidationUtil;
4243
import com.vaadin.flow.server.frontend.FrontendUtils;
4344
import com.vaadin.flow.server.frontend.TaskCleanFrontendFiles;
45+
import com.vaadin.flow.server.frontend.scanner.FrontendDependenciesScanner;
4446
import com.vaadin.flow.theme.Theme;
4547
import com.vaadin.pro.licensechecker.LicenseChecker;
4648

@@ -139,8 +141,22 @@ protected void executeInternal()
139141

140142
TaskCleanFrontendFiles cleanTask = new TaskCleanFrontendFiles(
141143
npmFolder(), frontendDirectory(), getClassFinder());
144+
145+
boolean reactEnabled = isReactEnabled()
146+
&& FrontendUtils.isReactRouterRequired(
147+
BuildFrontendUtil.getFrontendDirectory(this));
148+
FeatureFlags featureFlags = new FeatureFlags(
149+
createLookup(getClassFinder()));
150+
if (javaResourceFolder() != null) {
151+
featureFlags.setPropertiesLocation(javaResourceFolder());
152+
}
153+
FrontendDependenciesScanner frontendDependencies = new FrontendDependenciesScanner.FrontendDependenciesScannerFactory()
154+
.createScanner(!optimizeBundle, getClassFinder(),
155+
generateEmbeddableWebComponents, featureFlags,
156+
reactEnabled);
157+
142158
try {
143-
BuildFrontendUtil.runNodeUpdater(this);
159+
BuildFrontendUtil.runNodeUpdater(this, frontendDependencies);
144160
} catch (ExecutionFailedException | URISyntaxException exception) {
145161
throw new MojoFailureException(
146162
"Could not execute build-frontend goal", exception);
@@ -160,7 +176,8 @@ protected void executeInternal()
160176
}
161177
}
162178
LicenseChecker.setStrictOffline(true);
163-
boolean licenseRequired = BuildFrontendUtil.validateLicenses(this);
179+
boolean licenseRequired = BuildFrontendUtil.validateLicenses(this,
180+
frontendDependencies);
164181

165182
BuildFrontendUtil.updateBuildFile(this, licenseRequired);
166183

flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/BuildFrontendUtil.java

+11-7
Original file line numberDiff line numberDiff line change
@@ -311,12 +311,16 @@ public static File propagateBuildInfo(PluginAdapterBase adapter) {
311311
*
312312
* @param adapter
313313
* - the PluginAdapterBase.
314+
* @param frontendDependencies
315+
* Frontend dependencies scanner to use. If not set, one will be
316+
* initialized by {@link Options} class later.
314317
* @throws ExecutionFailedException
315318
* - a ExecutionFailedException.
316319
* @throws URISyntaxException
317320
* - - Could not build an URI from nodeDownloadRoot().
318321
*/
319-
public static void runNodeUpdater(PluginAdapterBuild adapter)
322+
public static void runNodeUpdater(PluginAdapterBuild adapter,
323+
FrontendDependenciesScanner frontendDependencies)
320324
throws ExecutionFailedException, URISyntaxException {
321325

322326
Set<File> jarFiles = adapter.getJarFiles();
@@ -365,7 +369,8 @@ public static void runNodeUpdater(PluginAdapterBuild adapter)
365369
.withFrontendExtraFileExtensions(
366370
adapter.frontendExtraFileExtensions())
367371
.withFrontendIgnoreVersionChecks(
368-
adapter.isFrontendIgnoreVersionChecks());
372+
adapter.isFrontendIgnoreVersionChecks())
373+
.withFrontendDependenciesScanner(frontendDependencies);
369374
new NodeTasks(options).execute();
370375
} catch (ExecutionFailedException exception) {
371376
throw exception;
@@ -577,10 +582,12 @@ private static void runFrontendBuildTool(PluginAdapterBase adapter,
577582
*
578583
* @param adapter
579584
* the PluginAdapterBase
585+
* @param frontendDependencies
580586
* @return {@literal true} if license validation is required because of the
581587
* presence of commercial components, otherwise {@literal false}.
582588
*/
583-
public static boolean validateLicenses(PluginAdapterBase adapter) {
589+
public static boolean validateLicenses(PluginAdapterBase adapter,
590+
FrontendDependenciesScanner frontendDependencies) {
584591
File outputFolder = adapter.webpackOutputDirectory();
585592

586593
String statsJsonContent = null;
@@ -609,11 +616,8 @@ public static boolean validateLicenses(PluginAdapterBase adapter) {
609616
statsJsonContent = "{}";
610617
}
611618

612-
FrontendDependenciesScanner scanner = new FrontendDependenciesScanner.FrontendDependenciesScannerFactory()
613-
.createScanner(false, adapter.getClassFinder(), true, null,
614-
adapter.isReactEnabled());
615619
List<Product> commercialComponents = findCommercialFrontendComponents(
616-
scanner, statsJsonContent);
620+
frontendDependencies, statsJsonContent);
617621
commercialComponents.addAll(findCommercialJavaComponents(adapter));
618622

619623
for (Product component : commercialComponents) {

flow-plugins/flow-plugin-base/src/test/java/com/vaadin/flow/plugin/base/BuildFrontendUtilTest.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import java.nio.file.Path;
1313
import java.nio.file.Paths;
1414
import java.util.ArrayList;
15-
import java.util.Arrays;
1615
import java.util.Collections;
1716
import java.util.HashMap;
1817
import java.util.HashSet;
@@ -41,6 +40,7 @@
4140
import com.vaadin.flow.server.Constants;
4241
import com.vaadin.flow.server.ExecutionFailedException;
4342
import com.vaadin.flow.server.InitParameters;
43+
import com.vaadin.flow.server.PwaConfiguration;
4444
import com.vaadin.flow.server.frontend.EndpointGeneratorTaskFactory;
4545
import com.vaadin.flow.server.frontend.FileIOUtils;
4646
import com.vaadin.flow.server.frontend.FrontendTools;
@@ -150,11 +150,15 @@ public void should_useHillaEngine_withNodeUpdater()
150150
.when(endpointGeneratorTaskFactory)
151151
.createTaskGenerateEndpoint(Mockito.any());
152152

153+
FrontendDependenciesScanner frontendDependencies = Mockito
154+
.mock(FrontendDependenciesScanner.class);
155+
Mockito.when(frontendDependencies.getPwaConfiguration())
156+
.thenReturn(new PwaConfiguration());
153157
try (MockedStatic<FrontendUtils> util = Mockito
154158
.mockStatic(FrontendUtils.class, Mockito.CALLS_REAL_METHODS)) {
155159
util.when(() -> FrontendUtils.isHillaUsed(Mockito.any(),
156160
Mockito.any())).thenReturn(true);
157-
BuildFrontendUtil.runNodeUpdater(adapter);
161+
BuildFrontendUtil.runNodeUpdater(adapter, frontendDependencies);
158162
}
159163

160164
Mockito.verify(lookup).lookup(EndpointGeneratorTaskFactory.class);
@@ -524,7 +528,11 @@ public void runNodeUpdater_generateFeatureFlagsJsFile() throws Exception {
524528
Mockito.when(adapter.createLookup(Mockito.any())).thenReturn(lookup);
525529
Mockito.doReturn(classFinder).when(lookup).lookup(ClassFinder.class);
526530

527-
BuildFrontendUtil.runNodeUpdater(adapter);
531+
FrontendDependenciesScanner frontendDependencies = Mockito
532+
.mock(FrontendDependenciesScanner.class);
533+
Mockito.when(frontendDependencies.getPwaConfiguration())
534+
.thenReturn(new PwaConfiguration());
535+
BuildFrontendUtil.runNodeUpdater(adapter, frontendDependencies);
528536

529537
File generatedFeatureFlagsFile = new File(adapter.generatedTsFolder(),
530538
FEATURE_FLAGS_FILE_NAME);

flow-server/src/main/java/com/vaadin/flow/server/frontend/NodeTasks.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,15 @@ public class NodeTasks implements FallibleCommand {
103103
* the options
104104
*/
105105
public NodeTasks(Options options) {
106+
FrontendDependenciesScanner frontendDependencies = options
107+
.getFrontendDependenciesScanner();
108+
106109
// Lock file is created in the project root folder and not in target/ so
107110
// that Maven does not remove it
108111
lockFile = new File(options.getNpmFolder(), ".vaadin-node-tasks.lock")
109112
.toPath();
110113

111114
ClassFinder classFinder = options.getClassFinder();
112-
FrontendDependenciesScanner frontendDependencies = null;
113115

114116
Set<String> webComponentTags = new HashSet<>();
115117

@@ -119,9 +121,6 @@ public NodeTasks(Options options) {
119121

120122
if (options.isEnablePackagesUpdate() || options.isEnableImportsUpdate()
121123
|| options.isEnableConfigUpdate()) {
122-
frontendDependencies = new FrontendDependenciesScanner.FrontendDependenciesScannerFactory()
123-
.createScanner(options);
124-
125124
if (options.isProductionMode()) {
126125
boolean needBuild = BundleValidationUtil.needsBuild(options,
127126
frontendDependencies,

flow-server/src/main/java/com/vaadin/flow/server/frontend/Options.java

+34
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.vaadin.flow.server.frontend.installer.NodeInstaller;
1818
import com.vaadin.flow.server.frontend.installer.Platform;
1919
import com.vaadin.flow.server.frontend.scanner.ClassFinder;
20+
import com.vaadin.flow.server.frontend.scanner.FrontendDependenciesScanner;
2021

2122
/**
2223
* Build a <code>NodeExecutor</code> instance.
@@ -85,6 +86,8 @@ public class Options implements Serializable {
8586

8687
private List<String> frontendExtraFileExtensions = null;
8788

89+
private FrontendDependenciesScanner frontendDependenciesScanner;
90+
8891
/**
8992
* The node.js version to be used when node.js is installed automatically by
9093
* Vaadin, for example <code>"v16.0.0"</code>. Defaults to
@@ -1037,4 +1040,35 @@ public Options withNpmExcludeWebComponents(boolean exclude) {
10371040
public boolean isFrontendIgnoreVersionChecks() {
10381041
return frontendIgnoreVersionChecks;
10391042
}
1043+
1044+
/**
1045+
* Sets the frontend dependencies scanner to use.
1046+
*
1047+
* @param frontendDependenciesScanner
1048+
* frontend dependencies scanner
1049+
* @return this builder
1050+
*/
1051+
public Options withFrontendDependenciesScanner(
1052+
FrontendDependenciesScanner frontendDependenciesScanner) {
1053+
this.frontendDependenciesScanner = frontendDependenciesScanner;
1054+
return this;
1055+
}
1056+
1057+
/**
1058+
* Gets the frontend dependencies scanner to use. If not is not pre-set,
1059+
* this initializes a new one based on the Options set.
1060+
*
1061+
* @return frontend dependencies scanner
1062+
*/
1063+
public FrontendDependenciesScanner getFrontendDependenciesScanner() {
1064+
if (frontendDependenciesScanner == null) {
1065+
boolean reactEnabled = isReactEnabled() && FrontendUtils
1066+
.isReactRouterRequired(getFrontendDirectory());
1067+
frontendDependenciesScanner = new FrontendDependenciesScanner.FrontendDependenciesScannerFactory()
1068+
.createScanner(!isUseByteCodeScanner(), getClassFinder(),
1069+
isGenerateEmbeddableWebComponents(),
1070+
getFeatureFlags(), reactEnabled);
1071+
}
1072+
return frontendDependenciesScanner;
1073+
}
10401074
}

flow-server/src/main/java/com/vaadin/flow/server/frontend/scanner/FrontendDependencies.java

+12
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,11 @@ public class FrontendDependencies extends AbstractDependenciesScanner {
107107
*
108108
* @param finder
109109
* the class finder
110+
* @deprecated Use
111+
* {@link FrontendDependencies#FrontendDependencies(ClassFinder, boolean, FeatureFlags, boolean)}
112+
* instead.
110113
*/
114+
@Deprecated
111115
public FrontendDependencies(ClassFinder finder) {
112116
this(finder, true, null);
113117
}
@@ -123,7 +127,11 @@ public FrontendDependencies(ClassFinder finder) {
123127
* {@link com.vaadin.flow.component.WebComponentExporter} classes
124128
* for dependencies. {@code true} is default for
125129
* {@link FrontendDependencies#FrontendDependencies(ClassFinder)}
130+
* @deprecated Use
131+
* {@link FrontendDependencies#FrontendDependencies(ClassFinder, boolean, FeatureFlags, boolean)}
132+
* instead.
126133
*/
134+
@Deprecated
127135
public FrontendDependencies(ClassFinder finder,
128136
boolean generateEmbeddableWebComponents) {
129137
this(finder, generateEmbeddableWebComponents, null);
@@ -142,7 +150,11 @@ public FrontendDependencies(ClassFinder finder,
142150
* {@link FrontendDependencies#FrontendDependencies(ClassFinder)}
143151
* @param featureFlags
144152
* available feature flags and their status
153+
* @deprecated Use
154+
* {@link FrontendDependencies#FrontendDependencies(ClassFinder, boolean, FeatureFlags, boolean)}
155+
* instead.
145156
*/
157+
@Deprecated
146158
public FrontendDependencies(ClassFinder finder,
147159
boolean generateEmbeddableWebComponents,
148160
FeatureFlags featureFlags) {

flow-server/src/main/java/com/vaadin/flow/server/frontend/scanner/FrontendDependenciesScanner.java

+38
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,11 @@ class FrontendDependenciesScannerFactory {
5959
* checks {@code WebComponentExporter} classes for
6060
* dependencies if {@code true}, doesn't check otherwise
6161
* @return a scanner implementation strategy
62+
* @deprecated Use
63+
* {@link FrontendDependenciesScannerFactory#createScanner(boolean, ClassFinder, boolean, FeatureFlags, boolean)}
64+
* instead.
6265
*/
66+
@Deprecated
6367
public FrontendDependenciesScanner createScanner(
6468
boolean allDependenciesScan, ClassFinder finder,
6569
boolean generateEmbeddableWebComponents) {
@@ -84,7 +88,11 @@ public FrontendDependenciesScanner createScanner(
8488
* available feature flags and their status
8589
* @return a scanner implementation strategy
8690
*
91+
* @deprecated Use
92+
* {@link FrontendDependenciesScannerFactory#createScanner(boolean, ClassFinder, boolean, FeatureFlags, boolean)}
93+
* instead.
8794
*/
95+
@Deprecated
8896
public FrontendDependenciesScanner createScanner(
8997
boolean allDependenciesScan, ClassFinder finder,
9098
boolean generateEmbeddableWebComponents,
@@ -93,6 +101,25 @@ public FrontendDependenciesScanner createScanner(
93101
generateEmbeddableWebComponents, featureFlags, true);
94102
}
95103

104+
/**
105+
* Produces scanner implementation based on {@code allDependenciesScan}
106+
* value.
107+
* <p>
108+
*
109+
* @param allDependenciesScan
110+
* if {@code true} then full classpath scanning strategy is
111+
* used, otherwise byte scanning strategy is produced
112+
* @param finder
113+
* a class finder
114+
* @param generateEmbeddableWebComponents
115+
* checks {@code WebComponentExporter} classes for
116+
* dependencies if {@code true}, doesn't check otherwise
117+
* @param featureFlags
118+
* available feature flags and their status
119+
* @param reactEnabled
120+
* {@code true} if react is enabled, {@code true otherwise}
121+
* @return a scanner implementation strategy
122+
*/
96123
public FrontendDependenciesScanner createScanner(
97124
boolean allDependenciesScan, ClassFinder finder,
98125
boolean generateEmbeddableWebComponents,
@@ -109,6 +136,17 @@ public FrontendDependenciesScanner createScanner(
109136
}
110137
}
111138

139+
/**
140+
* Produces scanner implementation based on the given Options object.
141+
*
142+
* @param options
143+
* Options to build the scanner from
144+
* @return a scanner implementation strategy
145+
* @deprecated Use
146+
* {@link FrontendDependenciesScannerFactory#createScanner(boolean, ClassFinder, boolean, FeatureFlags, boolean)}
147+
* instead.
148+
*/
149+
@Deprecated
112150
public FrontendDependenciesScanner createScanner(Options options) {
113151
boolean reactEnabled = options.isReactEnabled() && FrontendUtils
114152
.isReactRouterRequired(options.getFrontendDirectory());

flow-server/src/test/java/com/vaadin/flow/server/frontend/ComponentFlagsTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public void before() throws IOException {
7979
protected FrontendDependenciesScanner getScanner(ClassFinder finder,
8080
FeatureFlags featureFlags) {
8181
return new FrontendDependenciesScanner.FrontendDependenciesScannerFactory()
82-
.createScanner(false, finder, true, featureFlags);
82+
.createScanner(false, finder, true, featureFlags, true);
8383
}
8484

8585
@Test

0 commit comments

Comments
 (0)