Sitelet https://github.com/twitter/util/commit/3adca94a9e2b21a702aad619902ce5ef2e29de65
Skip to content

Commit 3adca94

Browse files
cacocojenkins
authored andcommitted
util-app: Fix ClassPath to deal with URLClassLoader#getURLs null
Summary: Problem/Solution We cannot rely on `URLClassLoader#getURLs` to not return a null instance. Update the code to protect against this possibility. See: google/guava#2239 Fixes issue #695. JIRA Issues: CSL-6530 Differential Revision: https://phabricator.twitter.biz/D181152
1 parent 56a421e commit 3adca94

3 files changed

Lines changed: 47 additions & 4 deletions

File tree

‎CHANGES‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,16 @@ Unreleased
99
API Changes:
1010

1111
* util-class-preloader: This library has been removed since it deprecated. We
12-
no longer recommend that people do this. ``PHAB_ID=D174250``
12+
no longer recommend that people do this. ``PHAB_ID=D174250``
1313

14+
Bug Fixes:
15+
16+
* util-app: Fix issue where in some environments, `URLClassLoader#getURLs` can
17+
return null, failing LoadService from initializing properly
18+
(see: https://github.com/google/guava/issues/2239). The `URLClassLoader` javadoc
19+
is not clear if a null can be returned when calling `URLClassLoader#getURLs` and for
20+
at least one application server, the default returned is null, thus we should be more
21+
resilient against this possibility. Fixes Finagle #695. ``PHAB_ID=D181152``
1422

1523
Deprecations:
1624

‎util-app/src/main/scala/com/twitter/app/ClassPath.scala‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,22 @@ private[app] sealed abstract class ClassPath[CpInfo <: ClassPath.Info] {
6161
buf
6262
}
6363

64-
private[this] def getEntries(loader: ClassLoader): Seq[(URI, ClassLoader)] = {
64+
// package protected for testing
65+
private[app] def getEntries(loader: ClassLoader): Seq[(URI, ClassLoader)] = {
6566
val ents = mutable.Buffer[(URI, ClassLoader)]()
6667
val parent = loader.getParent
6768
if (parent != null)
6869
ents ++= getEntries(parent)
6970

7071
loader match {
7172
case urlLoader: URLClassLoader =>
72-
for (url <- urlLoader.getURLs) {
73-
ents += (url.toURI -> loader)
73+
Option(urlLoader.getURLs) match {
74+
case Some(urls) =>
75+
urls.foreach { url =>
76+
if (url != null)
77+
ents += (url.toURI -> loader)
78+
}
79+
case _ =>
7480
}
7581
case _ =>
7682
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.twitter.app
2+
3+
import java.net.URLClassLoader
4+
import org.mockito.Mockito._
5+
import org.scalatest.FunSuite
6+
import org.scalatest.mockito.MockitoSugar
7+
8+
class ClassPathTest extends FunSuite with MockitoSugar {
9+
10+
test("Null URL[] URLClassloader") {
11+
val classLoader = mock[URLClassLoader]
12+
when(classLoader.getURLs).thenReturn(null)
13+
14+
val classPath = new LoadServiceClassPath()
15+
val entries = classPath.getEntries(classLoader)
16+
assert(entries.isEmpty)
17+
}
18+
19+
test("Null entry in URL[] from URLClassloader") {
20+
val urls = Array[java.net.URL](null)
21+
22+
val classLoader = mock[URLClassLoader]
23+
when(classLoader.getURLs).thenReturn(urls)
24+
25+
val classPath = new LoadServiceClassPath()
26+
val entries = classPath.getEntries(classLoader)
27+
assert(entries.isEmpty)
28+
}
29+
}

0 commit comments

Comments
 (0)