Skip to content

Commit ace9144

Browse files
authored
feat: expose application properties via Options for TypeScriptBootstrapModifier consumers (#24073) (CP: 24.10) (#24267)
`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 dfc6ee9 commit ace9144

3 files changed

Lines changed: 152 additions & 0 deletions

File tree

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

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
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+
*/
116
package com.vaadin.flow.server.frontend;
217

318
import java.io.File;
@@ -6,6 +21,7 @@
621
import java.util.ArrayList;
722
import java.util.List;
823
import java.util.Objects;
24+
import java.util.Optional;
925
import java.util.Set;
1026

1127
import com.fasterxml.jackson.databind.JsonNode;
@@ -18,6 +34,7 @@
1834
import com.vaadin.flow.server.frontend.installer.Platform;
1935
import com.vaadin.flow.server.frontend.scanner.ClassFinder;
2036
import com.vaadin.flow.server.frontend.scanner.FrontendDependenciesScanner;
37+
import com.vaadin.flow.server.startup.ApplicationConfiguration;
2138

2239
/**
2340
* Build a <code>NodeExecutor</code> instance.
@@ -143,6 +160,8 @@ public class Options implements Serializable {
143160

144161
private boolean commercialBannerEnabled = false;
145162

163+
private ApplicationConfiguration applicationConfiguration;
164+
146165
/**
147166
* Creates a new instance.
148167
*
@@ -172,6 +191,21 @@ public Options(Lookup lookup, ClassFinder classFinder, File npmFolder) {
172191
this.npmFolder = npmFolder;
173192
}
174193

194+
/**
195+
* Sets the application configuration for the current options and returns
196+
* the updated options instance.
197+
*
198+
* @param applicationConfiguration
199+
* the application configuration to be applied
200+
* @return the updated {@code Options} instance with the specified
201+
* application configuration
202+
*/
203+
public Options withApplicationConfiguration(
204+
ApplicationConfiguration applicationConfiguration) {
205+
this.applicationConfiguration = applicationConfiguration;
206+
return this;
207+
}
208+
175209
/**
176210
* Sets the directory containing the project's frontend files
177211
*
@@ -1125,4 +1159,42 @@ public boolean copyAssets() {
11251159
}
11261160
return copyAssets;
11271161
}
1162+
1163+
/**
1164+
* Retrieves the value of a string application property.
1165+
* <p>
1166+
* Returns an empty {@code Optional} if the application configuration is not
1167+
* available (e.g., at build time). When configuration is available, returns
1168+
* the property value or the given default.
1169+
*
1170+
* @param name
1171+
* the name of the property to retrieve
1172+
* @param defaultValue
1173+
* the value to return if the property is not set
1174+
* @return the property value, or empty if configuration is unavailable
1175+
*/
1176+
public Optional<String> getApplicationStringProperty(String name,
1177+
String defaultValue) {
1178+
return Optional.ofNullable(applicationConfiguration)
1179+
.map(app -> app.getStringProperty(name, defaultValue));
1180+
}
1181+
1182+
/**
1183+
* Retrieves the value of a boolean application property.
1184+
* <p>
1185+
* Returns an empty {@code Optional} if the application configuration is not
1186+
* available (e.g., at build time). When configuration is available, returns
1187+
* the property value or the given default.
1188+
*
1189+
* @param name
1190+
* the name of the property to retrieve
1191+
* @param defaultValue
1192+
* the value to return if the property is not set
1193+
* @return the property value, or empty if configuration is unavailable
1194+
*/
1195+
public Optional<Boolean> getApplicationBooleanProperty(String name,
1196+
boolean defaultValue) {
1197+
return Optional.ofNullable(applicationConfiguration)
1198+
.map(app -> app.getBooleanProperty(name, defaultValue));
1199+
}
11281200
}
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
@@ -252,6 +252,7 @@ public static DevModeHandler initDevModeHandler(Set<Class<?>> classes,
252252
ClassFinder.class);
253253
Lookup lookup = Lookup.compose(lookupForClassFinder, lookupFromContext);
254254
Options options = new Options(lookup, baseDir)
255+
.withApplicationConfiguration(config)
255256
.withFrontendDirectory(frontendFolder)
256257
.withFrontendGeneratedFolder(
257258
new File(frontendFolder + GENERATED))

0 commit comments

Comments
 (0)