Skip to content

Commit addcba0

Browse files
authored
feat: expose application properties via Options for TypeScriptBootstrapModifier consumers (#24073) (CP: 25.0) (#24252)
`TypeScriptBootstrapModifier` implementations (e.g., Copilot) need access to application properties to conditionally modify bootstrap TypeScript. Currently, the Copilot script is injected in dev mode regardless of whether Copilot is enabled in the project configuration. Add `withApplicationConfiguration` to `Options` and property accessor methods (`getApplicationStringProperty`, `getApplicationBooleanProperty`) that return `Optional.empty()` when configuration is unavailable (build time). Wire `ApplicationConfiguration` from `DevModeInitializer`. Fixes #24055
1 parent 88e2947 commit addcba0

3 files changed

Lines changed: 137 additions & 0 deletions

File tree

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

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.ArrayList;
2222
import java.util.List;
2323
import java.util.Objects;
24+
import java.util.Optional;
2425
import java.util.Set;
2526

2627
import org.slf4j.LoggerFactory;
@@ -33,6 +34,7 @@
3334
import com.vaadin.flow.server.frontend.installer.Platform;
3435
import com.vaadin.flow.server.frontend.scanner.ClassFinder;
3536
import com.vaadin.flow.server.frontend.scanner.FrontendDependenciesScanner;
37+
import com.vaadin.flow.server.startup.ApplicationConfiguration;
3638

3739
/**
3840
* Build a <code>NodeExecutor</code> instance.
@@ -163,6 +165,8 @@ public class Options implements Serializable {
163165

164166
private boolean commercialBannerEnabled = false;
165167

168+
private ApplicationConfiguration applicationConfiguration;
169+
166170
/**
167171
* Creates a new instance.
168172
*
@@ -192,6 +196,21 @@ public Options(Lookup lookup, ClassFinder classFinder, File npmFolder) {
192196
this.npmFolder = npmFolder;
193197
}
194198

199+
/**
200+
* Sets the application configuration for the current options and returns
201+
* the updated options instance.
202+
*
203+
* @param applicationConfiguration
204+
* the application configuration to be applied
205+
* @return the updated {@code Options} instance with the specified
206+
* application configuration
207+
*/
208+
public Options withApplicationConfiguration(
209+
ApplicationConfiguration applicationConfiguration) {
210+
this.applicationConfiguration = applicationConfiguration;
211+
return this;
212+
}
213+
195214
/**
196215
* Sets the directory containing the project's frontend files
197216
*
@@ -1139,4 +1158,42 @@ public Options withMetaInfResourcesDirectory(File resourcesDirectory) {
11391158
public File getMetaInfResourcesDirectory() {
11401159
return resourcesDirectory;
11411160
}
1161+
1162+
/**
1163+
* Retrieves the value of a string application property.
1164+
* <p>
1165+
* Returns an empty {@code Optional} if the application configuration is not
1166+
* available (e.g., at build time). When configuration is available, returns
1167+
* the property value or the given default.
1168+
*
1169+
* @param name
1170+
* the name of the property to retrieve
1171+
* @param defaultValue
1172+
* the value to return if the property is not set
1173+
* @return the property value, or empty if configuration is unavailable
1174+
*/
1175+
public Optional<String> getApplicationStringProperty(String name,
1176+
String defaultValue) {
1177+
return Optional.ofNullable(applicationConfiguration)
1178+
.map(app -> app.getStringProperty(name, defaultValue));
1179+
}
1180+
1181+
/**
1182+
* Retrieves the value of a boolean application property.
1183+
* <p>
1184+
* Returns an empty {@code Optional} if the application configuration is not
1185+
* available (e.g., at build time). When configuration is available, returns
1186+
* the property value or the given default.
1187+
*
1188+
* @param name
1189+
* the name of the property to retrieve
1190+
* @param defaultValue
1191+
* the value to return if the property is not set
1192+
* @return the property value, or empty if configuration is unavailable
1193+
*/
1194+
public Optional<Boolean> getApplicationBooleanProperty(String name,
1195+
boolean defaultValue) {
1196+
return Optional.ofNullable(applicationConfiguration)
1197+
.map(app -> app.getBooleanProperty(name, defaultValue));
1198+
}
11421199
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright 2000-2026 Vaadin Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package com.vaadin.flow.server.frontend;
17+
18+
import java.io.File;
19+
import java.util.Optional;
20+
21+
import org.junit.Test;
22+
import org.mockito.Mockito;
23+
24+
import com.vaadin.flow.server.startup.ApplicationConfiguration;
25+
import com.vaadin.tests.util.MockOptions;
26+
27+
import static org.junit.Assert.assertEquals;
28+
import static org.junit.Assert.assertTrue;
29+
30+
public class OptionsApplicationPropertiesTest {
31+
32+
@Test
33+
public void getApplicationBooleanProperty_configAvailable_returnsPropertyValue() {
34+
ApplicationConfiguration config = Mockito
35+
.mock(ApplicationConfiguration.class);
36+
Mockito.when(config.getBooleanProperty("test.prop", false))
37+
.thenReturn(true);
38+
39+
Options options = new MockOptions(new File("."))
40+
.withApplicationConfiguration(config);
41+
42+
Optional<Boolean> result = options
43+
.getApplicationBooleanProperty("test.prop", false);
44+
assertEquals(Optional.of(true), result);
45+
}
46+
47+
@Test
48+
public void getApplicationBooleanProperty_noConfig_returnsEmpty() {
49+
Options options = new MockOptions(new File("."));
50+
51+
Optional<Boolean> result = options
52+
.getApplicationBooleanProperty("test.prop", true);
53+
assertTrue(result.isEmpty());
54+
}
55+
56+
@Test
57+
public void getApplicationStringProperty_configAvailable_returnsPropertyValue() {
58+
ApplicationConfiguration config = Mockito
59+
.mock(ApplicationConfiguration.class);
60+
Mockito.when(config.getStringProperty("test.prop", "default"))
61+
.thenReturn("custom");
62+
63+
Options options = new MockOptions(new File("."))
64+
.withApplicationConfiguration(config);
65+
66+
Optional<String> result = options
67+
.getApplicationStringProperty("test.prop", "default");
68+
assertEquals(Optional.of("custom"), result);
69+
}
70+
71+
@Test
72+
public void getApplicationStringProperty_noConfig_returnsEmpty() {
73+
Options options = new MockOptions(new File("."));
74+
75+
Optional<String> result = options
76+
.getApplicationStringProperty("test.prop", "default");
77+
assertTrue(result.isEmpty());
78+
}
79+
}

vaadin-dev-server/src/main/java/com/vaadin/base/devserver/startup/DevModeInitializer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ public static DevModeHandler initDevModeHandler(Set<Class<?>> classes,
223223
ClassFinder.class);
224224
Lookup lookup = Lookup.compose(lookupForClassFinder, lookupFromContext);
225225
Options options = new Options(lookup, baseDir)
226+
.withApplicationConfiguration(config)
226227
.withFrontendDirectory(frontendFolder)
227228
.withFrontendGeneratedFolder(
228229
new File(frontendFolder + GENERATED))

0 commit comments

Comments
 (0)