Content is user-generated and unverified.

Error Analysis

Based on the error message and code you've shared, I can identify the issue and provide some suggestions for fixing it. Let me analyze what's happening.

The error you're seeing is a java.nio.file.FileSystemNotFoundException that occurs when JabRef tries to load an internal style. Looking at the stack trace and code, here's what's happening:

  1. The error occurs in JStyle.java at line 285 in the reload() method, specifically at the call to Path.of(resUrl.toURI()).
  2. The issue appears when attempting to access a resource inside the JAR file using a URI that's being converted to a Path object.
  3. The error is specific to the development build and doesn't occur in the MSI installation, suggesting it's related to how resources are accessed in different environments.

Root Cause

The problem is in the reload() method of JStyle.java when it tries to handle resources from inside a JAR file. Java's Path.of() method can't directly work with JAR URIs (which have the format jar:file:/path/to/file.jar!/internal/path) without a proper FileSystem provider.

When JabRef tries to load an internal style from a resource in the JAR using Path.of(resUrl.toURI()), it fails because the default file system doesn't know how to handle JAR URIs.

Solution

You need to modify the reload() method in JStyle.java to correctly handle resources inside JARs. Here's a suggested fix:

java
private void reload() throws IOException {
    if (styleFile != null) {
        if (fromResource) {
            try {
                URL resUrl = JStyle.class.getResource(path);
                if (resUrl != null) {
                    // Don't try to convert JAR URLs directly to Path objects
                    try (InputStream stream = resUrl.openStream()) {
                        initialize(stream);
                        // Update the modification time to current time for resources
                        this.styleFileModificationTime = System.currentTimeMillis();
                    }
                    return; // Return early after handling the resource
                }
            } catch (Exception ex) {
                LOGGER.error("Couldn't resolve resource path for style {}", path, ex);
            }
        }
        
        // Handle files on disk (non-resources)
        Path resourcePath = styleFile;
        this.styleFileModificationTime = Files.getLastModifiedTime(resourcePath).toMillis();
        try (InputStream stream = Files.newInputStream(resourcePath)) {
            initialize(stream);
        }
    }
}

This approach:

  1. Uses openStream() to get a direct stream from the URL rather than trying to convert it to a Path
  2. Handles resources and regular files differently
  3. Sets a reasonable modification time for resources (current time, since we can't get the actual modification time from JAR resources)

Alternative Approaches

If you prefer to maintain a structure closer to the original, you could also use the ZipFileSystem approach to properly handle JAR URIs:

java
private void reload() throws IOException {
    if (styleFile != null) {
        if (fromResource) {
            try {
                URL resUrl = JStyle.class.getResource(path);
                if (resUrl != null) {
                    URI uri = resUrl.toURI();
                    
                    // If it's a JAR URI, open it with the appropriate FileSystem
                    if ("jar".equals(uri.getScheme())) {
                        try {
                            FileSystem fs = FileSystems.getFileSystem(uri);
                            Path resourcePath = fs.getPath(uri.getPath());
                            this.styleFileModificationTime = System.currentTimeMillis();
                            try (InputStream stream = Files.newInputStream(resourcePath)) {
                                initialize(stream);
                            }
                            return;
                        } catch (FileSystemNotFoundException e) {
                            // FileSystem doesn't exist yet, need to create it
                            Map<String, String> env = new HashMap<>();
                            String[] parts = uri.toString().split("!");
                            try (FileSystem fs = FileSystems.newFileSystem(URI.create(parts[0]), env)) {
                                Path resourcePath = fs.getPath(parts[1]);
                                this.styleFileModificationTime = System.currentTimeMillis();
                                try (InputStream stream = Files.newInputStream(resourcePath)) {
                                    initialize(stream);
                                }
                                return;
                            }
                        }
                    } else {
                        // Regular file URI
                        Path resourcePath = Path.of(uri);
                        this.styleFileModificationTime = Files.getLastModifiedTime(resourcePath).toMillis();
                        try (InputStream stream = Files.newInputStream(resourcePath)) {
                            initialize(stream);
                        }
                        return;
                    }
                }
            } catch (URISyntaxException ex) {
                LOGGER.error("Couldn't resolve resource path for style {}", path, ex);
            }
        }
        
        // Fall back to direct file access if it's not a resource or resource loading failed
        this.styleFileModificationTime = Files.getLastModifiedTime(styleFile).toMillis();
        try (InputStream stream = Files.newInputStream(styleFile)) {
            initialize(stream);
        }
    }
}

Simplest Fix

If you want the simplest possible fix, just modify the current code to avoid using Path.of() for resource URLs:

java
private void reload() throws IOException {
    if (styleFile != null) {
        if (fromResource) {
            URL resUrl = JStyle.class.getResource(path);
            if (resUrl != null) {
                // Don't use Path.of() for resources
                try (InputStream stream = resUrl.openStream()) {
                    initialize(stream);
                    this.styleFileModificationTime = System.currentTimeMillis();
                    return;
                }
            }
        }
        
        // Original code for non-resource files
        this.styleFileModificationTime = Files.getLastModifiedTime(styleFile).toMillis();
        try (InputStream stream = Files.newInputStream(styleFile)) {
            initialize(stream);
        }
    }
}

This should resolve the issue by using the appropriate method to access resources inside JARs, while maintaining the existing behavior for files on disk.

Content is user-generated and unverified.
    JabRef JStyle Error Analysis | Claude