Skip to content

Commit debd303

Browse files
authored
fix FileSystemAlreadyExistsException with package scanner (#4204)
* work around exception * update readme
1 parent e456514 commit debd303

File tree

2 files changed

+20
-3
lines changed

2 files changed

+20
-3
lines changed

CHANGELOG.next-release.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ This file contains all changes which are not released yet.
99

1010
# Fixes
1111
<!--FIXES-START-->
12-
* Fix async httpclient 5.x instrumentation- [#4185](https://github.com/elastic/apm-agent-java/pull/4185)
12+
* Fix async httpclient 5.x instrumentation - [#4185](https://github.com/elastic/apm-agent-java/pull/4185)
13+
* Prevent `FileSystemAlreadyExistsException` on single-jar application startup - [#4204](https://github.com/elastic/apm-agent-java/pull/4204)
1314

1415
<!--FIXES-END-->
1516
# Features and enhancements

apm-agent-core/src/main/java/co/elastic/apm/agent/util/PackageScanner.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
*/
1919
package co.elastic.apm.agent.util;
2020

21+
import javax.annotation.Nullable;
2122
import java.io.File;
2223
import java.io.IOException;
2324
import java.net.URI;
2425
import java.net.URISyntaxException;
2526
import java.net.URL;
2627
import java.nio.channels.ClosedByInterruptException;
2728
import java.nio.file.FileSystem;
29+
import java.nio.file.FileSystemAlreadyExistsException;
2830
import java.nio.file.FileSystems;
2931
import java.nio.file.FileVisitResult;
3032
import java.nio.file.Files;
@@ -86,9 +88,8 @@ private static List<String> doGetClassNames(String basePackage, ClassLoader clas
8688
URI uri = resource.toURI();
8789
List<String> result;
8890
if (uri.getScheme().equals("jar")) {
89-
// avoids FileSystemAlreadyExistsException
9091
synchronized (PackageScanner.class) {
91-
try (FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap())) {
92+
try (FileSystem fileSystem = getFileSystem(uri)) {
9293
Path basePath = fileSystem.getPath(baseFolderResource).toAbsolutePath();
9394
if (!Files.exists(basePath)) { // called in a privileged action, thus no need to deal with security manager
9495
basePath = fileSystem.getPath("agent/" + baseFolderResource).toAbsolutePath();
@@ -104,6 +105,21 @@ private static List<String> doGetClassNames(String basePackage, ClassLoader clas
104105
return classNames;
105106
}
106107

108+
@Nullable
109+
private static FileSystem getFileSystem(URI uri) throws IOException {
110+
FileSystem fileSystem;
111+
// FileSystemAlreadyExistsException is thrown when FS has already been opened
112+
// FileSystemNotFoundException is thrown when FS has not already been opened
113+
// thus we can't avoid throwing exceptions, but we can use them for transparent fallback
114+
// multiple calls for equivalent URIs is expected with "fat jar" that have nested paths with "!/../path/within/jar"
115+
try {
116+
fileSystem = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap());
117+
} catch (FileSystemAlreadyExistsException e) {
118+
fileSystem = FileSystems.getFileSystem(uri);
119+
}
120+
return fileSystem;
121+
}
122+
107123
/**
108124
* Lists all classes in the provided path, as part of the provided base package
109125
* @param basePackage the package to prepend to all class files found in the relative path

0 commit comments

Comments
 (0)