Skip to content
This repository was archived by the owner on May 28, 2018. It is now read-only.

Commit 66d1dc0

Browse files
committed
Merge pull request #132 from Stephan202/jar-file-scanner-fix
Fix various issues with JarFileScanner
2 parents bc6a3dd + 2a20225 commit 66d1dc0

File tree

2 files changed

+72
-34
lines changed

2 files changed

+72
-34
lines changed

core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarFileScanner.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public final class JarFileScanner implements ResourceFinder {
5858

5959
private static final Logger LOGGER = Logger.getLogger(JarFileScanner.class.getName());
6060
// platform independent file separator within the jar file
61-
private static final char JAR_FILE_SEPARATOR = '\\';
61+
private static final char JAR_FILE_SEPARATOR = '/';
6262

6363
private final JarInputStream jarInputStream;
6464
private final String parent;
@@ -91,14 +91,17 @@ public boolean hasNext() {
9191
break;
9292
}
9393
if (!next.isDirectory() && next.getName().startsWith(parent)) {
94+
final String suffix = next.getName().substring(parent.length());
9495
if (recursive) {
9596
// accept any entries with the prefix
96-
break;
97-
}
98-
// accept only entries directly in the folder.
99-
final String suffix = next.getName().substring(parent.length());
100-
if (suffix.lastIndexOf(JAR_FILE_SEPARATOR) <= 0) {
101-
break;
97+
if (parent.isEmpty() || suffix.indexOf(JAR_FILE_SEPARATOR) == 0) {
98+
break;
99+
}
100+
} else {
101+
// accept only entries directly in the folder.
102+
if (suffix.lastIndexOf(JAR_FILE_SEPARATOR) == (parent.isEmpty() ? -1 : 0)) {
103+
break;
104+
}
102105
}
103106
}
104107
} while (true);

core-server/src/test/java/org/glassfish/jersey/server/internal/scanning/JarFileScannerTest.java

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,33 @@
4040
package org.glassfish.jersey.server.internal.scanning;
4141

4242
import java.io.FileInputStream;
43+
import java.io.IOException;
4344
import java.io.InputStream;
4445
import java.util.Enumeration;
4546
import java.util.jar.JarEntry;
4647
import java.util.jar.JarFile;
48+
import java.util.regex.Pattern;
4749

4850
import org.junit.Before;
4951
import org.junit.Test;
52+
import org.junit.experimental.theories.DataPoint;
53+
import org.junit.experimental.theories.Theories;
54+
import org.junit.experimental.theories.Theory;
55+
import org.junit.runner.RunWith;
5056
import static org.hamcrest.CoreMatchers.equalTo;
57+
import static org.junit.Assert.assertFalse;
5158
import static org.junit.Assert.assertThat;
5259
import static org.junit.Assert.fail;
5360

5461
/**
5562
* @author Martin Snyder
5663
*/
64+
@RunWith(Theories.class)
5765
public class JarFileScannerTest {
66+
@DataPoint
67+
public static final boolean RECURSIVE = true;
68+
@DataPoint
69+
public static final boolean NON_RECURSIVE = false;
5870

5971
private String jaxRsApiPath;
6072

@@ -75,55 +87,78 @@ public void setUp() throws Exception {
7587
}
7688
}
7789

78-
/**
79-
* Test case for JERSEY-2197, JERSEY-2175.
80-
*/
8190
@Test
82-
public void testClassEnumeration() throws Exception {
83-
// Count actual entries.
84-
final JarFile jarFile = new JarFile(jaxRsApiPath);
91+
public void testRecursiveResourceEnumerationOfAllPackages() throws IOException {
92+
final int actualEntries = countJarEntriesByPattern(Pattern.compile(".*\\.(class|properties|xml)"));
93+
final int scannedEntries = countJarEntriesUsingScanner("", true);
94+
assertThat("Failed to enumerate all contents of javax.ws.rs-api", scannedEntries, equalTo(actualEntries));
95+
}
8596

86-
int actualEntries = 0;
87-
try {
88-
final Enumeration<JarEntry> entries = jarFile.entries();
97+
@Test
98+
public void testRecursiveClassEnumerationWithExistantPackage() throws IOException {
99+
final int actualEntries = countJarEntriesByPattern(Pattern.compile("javax/ws/rs/.*\\.class"));
100+
final int scannedEntries = countJarEntriesUsingScanner("javax/ws/rs", true);
101+
assertThat("Failed to enumerate all contents of javax.ws.rs-api", scannedEntries, equalTo(actualEntries));
102+
}
89103

104+
@Test
105+
public void testNonRecursiveClassEnumerationWithExistantPackage() throws IOException {
106+
final int actualEntries = countJarEntriesByPattern(Pattern.compile("javax/ws/rs/[^/]*\\.class"));
107+
final int scannedEntries = countJarEntriesUsingScanner("javax/ws/rs", false);
108+
assertThat("Failed to enumerate package 'javax.ws.rs' of javax.ws.rs-api", scannedEntries, equalTo(actualEntries));
109+
}
110+
111+
private int countJarEntriesByPattern(final Pattern pattern) throws IOException {
112+
int matchingEntries = 0;
113+
114+
try (final JarFile jarFile = new JarFile(this.jaxRsApiPath)) {
115+
final Enumeration<JarEntry> entries = jarFile.entries();
90116
while (entries.hasMoreElements()) {
91117
final JarEntry entry = entries.nextElement();
92-
93-
if (entry.getName().endsWith(".class")) {
94-
actualEntries++;
118+
if (pattern.matcher(entry.getName()).matches()) {
119+
matchingEntries++;
95120
}
96121
}
97-
} finally {
98-
jarFile.close();
99122
}
100123

101-
// Scan entries using Jersey scanner.
102-
final InputStream jaxRsApi = new FileInputStream(jaxRsApiPath);
124+
return matchingEntries;
125+
}
103126

104-
try {
105-
final JarFileScanner jarFileScanner = new JarFileScanner(jaxRsApi, "javax/ws/rs", true);
127+
private int countJarEntriesUsingScanner(final String parent, final boolean recursive) throws IOException {
128+
int scannedEntryCount = 0;
106129

107-
int scannedEntryCount = 0;
130+
try (final InputStream jaxRsApi = new FileInputStream(this.jaxRsApiPath)) {
131+
final JarFileScanner jarFileScanner = new JarFileScanner(jaxRsApi, parent, recursive);
108132
while (jarFileScanner.hasNext()) {
109133
// Fetch next entry.
110134
jarFileScanner.next();
111135

136+
// JERSEY-2175 and JERSEY-2197:
112137
// This test doesn't actually do anything with the input stream, but it is important that it
113138
// open/close the stream to simulate actual usage. The reported defect is only exposed if you
114139
// call open/close in some fashion.
115-
final InputStream classStream = jarFileScanner.open();
116-
117-
try {
140+
try (final InputStream classStream = jarFileScanner.open()) {
118141
scannedEntryCount++;
119-
} finally {
120-
classStream.close();
121142
}
122143
}
144+
}
145+
146+
return scannedEntryCount;
147+
}
148+
149+
@Theory
150+
public void testClassEnumerationWithNonexistentPackage(final boolean recursive) throws IOException {
151+
try (final InputStream jaxRsApi = new FileInputStream(this.jaxRsApiPath)) {
152+
final JarFileScanner jarFileScanner = new JarFileScanner(jaxRsApi, "javax/ws/r", recursive);
153+
assertFalse("Unexpectedly found package 'javax.ws.r' in javax.ws.rs-api", jarFileScanner.hasNext());
154+
}
155+
}
123156

124-
assertThat("Failed to enumerate all contents of javax.ws.rs-api.", scannedEntryCount, equalTo(actualEntries));
125-
} finally {
126-
jaxRsApi.close();
157+
@Theory
158+
public void testClassEnumerationWithClassPrefix(final boolean recursive) throws IOException {
159+
try (final InputStream jaxRsApi = new FileInputStream(this.jaxRsApiPath)) {
160+
final JarFileScanner jarFileScanner = new JarFileScanner(jaxRsApi, "javax/ws/rs/GE", recursive);
161+
assertFalse("Unexpectedly found package 'javax.ws.rs.GE' in javax.ws.rs-api", jarFileScanner.hasNext());
127162
}
128163
}
129164
}

0 commit comments

Comments
 (0)