Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
import com.vaadin.flow.server.communication.IndexHtmlRequestListener;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.Optional;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Service initialization listener that automatically applies a dynamic theme.
Expand All @@ -19,23 +24,51 @@
@SuppressWarnings("serial")
public class DynamicThemeInitializer implements VaadinServiceInitListener {

private static final Logger logger = LoggerFactory.getLogger(DynamicThemeInitializer.class);

private static final String PROPERTIES_PATH = "META-INF/dynamic-theme.properties";

@Override
public void serviceInit(ServiceInitEvent event) {
if (DynamicTheme.isFeatureSupported()) {
try (InputStream in = getClass().getResourceAsStream("/META-INF/dynamic-theme.properties")) {
if (in != null) {
Properties props = new Properties();
props.load(in);
String themeName = props.getProperty("theme");
if (themeName != null) {
DynamicTheme theme = DynamicTheme.valueOf(themeName.trim());
try {
Enumeration<URL> resources = getClass().getClassLoader().getResources(PROPERTIES_PATH);
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
String source = getSourceName(url);
readTheme(url).ifPresent(theme -> {
logger.info("Applying dynamic theme '{}' from {}", theme, source);
event.addIndexHtmlRequestListener(theme::initialize);
}
});
}
} catch (IOException e) {
throw new RuntimeException("Error reading dynamic-theme.properties", e);
}
}
}

private Optional<DynamicTheme> readTheme(URL url) throws IOException {
try (InputStream in = url.openStream()) {
Properties props = new Properties();
props.load(in);
String themeName = props.getProperty("theme");
return Optional.ofNullable(themeName).map(String::trim).map(DynamicTheme::valueOf);
}
}
Comment on lines +50 to +57
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Silent skip when theme property is missing from a discovered file.

If a dynamic-theme.properties file is found but doesn't contain the theme key (e.g., typo like themes=LUMO), readTheme returns an empty Optional and nothing is logged. Given that this class now explicitly scans for these files, a missing property is likely a configuration error and should at least be logged as a warning.

Proposed fix
   private Optional<DynamicTheme> readTheme(URL url) throws IOException {
     try (InputStream in = url.openStream()) {
       Properties props = new Properties();
       props.load(in);
       String themeName = props.getProperty("theme");
+      if (themeName == null || themeName.trim().isEmpty()) {
+        logger.warn("No 'theme' property found in {}", url);
+        return Optional.empty();
+      }
-      return Optional.ofNullable(themeName).map(String::trim).map(DynamicTheme::valueOf);
+      return Optional.of(DynamicTheme.valueOf(themeName.trim()));
     }
   }
🤖 Prompt for AI Agents
In
`@src/main/java/com/flowingcode/vaadin/addons/demo/DynamicThemeInitializer.java`
around lines 50 - 57, The readTheme method currently returns empty silently when
the "theme" property is missing or invalid; update readTheme to (1) after
loading props check if props.getProperty("theme") is null or blank and log a
warning including the URL to indicate a misconfigured dynamic-theme.properties,
and (2) when mapping to DynamicTheme via DynamicTheme.valueOf, catch
IllegalArgumentException, log an error mentioning the invalid value and the URL,
and return Optional.empty; use the class logger (e.g., LOGGER or logger) for
these messages and keep the method signature and stream handling as-is.


// Extracts a short, readable source name from the URL.
private String getSourceName(URL url) {
String path = url.getPath();
// JAR URLs look like: file:/path/to/file.jar!/META-INF/...
int jarSeparator = path.indexOf("!/");
if (jarSeparator > 0) {
path = path.substring(0, jarSeparator);
int lastSlash = path.lastIndexOf('/');
if (lastSlash >= 0) {
return path.substring(lastSlash + 1);
}
}
return url.toString();
}

}