Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
d9d26cba
Commit
d9d26cba
authored
Jun 17, 2016
by
Andy Wilkinson
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch '1.3.x'
parents
a273d8d0
13635201
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
115 additions
and
1 deletion
+115
-1
SilentExitExceptionHandler.java
...ork/boot/devtools/restart/SilentExitExceptionHandler.java
+41
-1
SilentExitExceptionHandlerTests.java
...oot/devtools/restart/SilentExitExceptionHandlerTests.java
+74
-0
No files found.
spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/SilentExitExceptionHandler.java
View file @
d9d26cba
/*
/*
* Copyright 2012-201
5
the original author or authors.
* Copyright 2012-201
6
the original author or authors.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License.
...
@@ -17,11 +17,13 @@
...
@@ -17,11 +17,13 @@
package
org
.
springframework
.
boot
.
devtools
.
restart
;
package
org
.
springframework
.
boot
.
devtools
.
restart
;
import
java.lang.Thread.UncaughtExceptionHandler
;
import
java.lang.Thread.UncaughtExceptionHandler
;
import
java.util.Arrays
;
/**
/**
* {@link UncaughtExceptionHandler} decorator that allows a thread to exit silently.
* {@link UncaughtExceptionHandler} decorator that allows a thread to exit silently.
*
*
* @author Phillip Webb
* @author Phillip Webb
* @author Andy Wilkinson
*/
*/
class
SilentExitExceptionHandler
implements
UncaughtExceptionHandler
{
class
SilentExitExceptionHandler
implements
UncaughtExceptionHandler
{
...
@@ -34,6 +36,9 @@ class SilentExitExceptionHandler implements UncaughtExceptionHandler {
...
@@ -34,6 +36,9 @@ class SilentExitExceptionHandler implements UncaughtExceptionHandler {
@Override
@Override
public
void
uncaughtException
(
Thread
thread
,
Throwable
exception
)
{
public
void
uncaughtException
(
Thread
thread
,
Throwable
exception
)
{
if
(
exception
instanceof
SilentExitException
)
{
if
(
exception
instanceof
SilentExitException
)
{
if
(
jvmWillExit
(
thread
))
{
preventNonZeroExitCode
();
}
return
;
return
;
}
}
if
(
this
.
delegate
!=
null
)
{
if
(
this
.
delegate
!=
null
)
{
...
@@ -53,6 +58,41 @@ class SilentExitExceptionHandler implements UncaughtExceptionHandler {
...
@@ -53,6 +58,41 @@ class SilentExitExceptionHandler implements UncaughtExceptionHandler {
throw
new
SilentExitException
();
throw
new
SilentExitException
();
}
}
private
boolean
jvmWillExit
(
Thread
exceptionThread
)
{
for
(
Thread
thread
:
getAllThreads
())
{
if
(
thread
!=
exceptionThread
&&
thread
.
isAlive
()
&&
!
thread
.
isDaemon
())
{
return
false
;
}
}
return
true
;
}
protected
void
preventNonZeroExitCode
()
{
System
.
exit
(
0
);
}
protected
Thread
[]
getAllThreads
()
{
ThreadGroup
rootThreadGroup
=
getRootThreadGroup
();
int
size
=
32
;
int
threadCount
;
Thread
[]
threads
;
do
{
size
*=
2
;
threads
=
new
Thread
[
size
];
threadCount
=
rootThreadGroup
.
enumerate
(
threads
);
}
while
(
threadCount
==
threads
.
length
);
return
Arrays
.
copyOf
(
threads
,
threadCount
);
}
private
ThreadGroup
getRootThreadGroup
()
{
ThreadGroup
candidate
=
Thread
.
currentThread
().
getThreadGroup
();
while
(
candidate
.
getParent
()
!=
null
)
{
candidate
=
candidate
.
getParent
();
}
return
candidate
;
}
private
static
class
SilentExitException
extends
RuntimeException
{
private
static
class
SilentExitException
extends
RuntimeException
{
}
}
...
...
spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/SilentExitExceptionHandlerTests.java
View file @
d9d26cba
...
@@ -16,6 +16,8 @@
...
@@ -16,6 +16,8 @@
package
org
.
springframework
.
boot
.
devtools
.
restart
;
package
org
.
springframework
.
boot
.
devtools
.
restart
;
import
java.util.concurrent.CountDownLatch
;
import
org.junit.Test
;
import
org.junit.Test
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
...
@@ -55,6 +57,24 @@ public class SilentExitExceptionHandlerTests {
...
@@ -55,6 +57,24 @@ public class SilentExitExceptionHandlerTests {
assertThat
(
testThread
.
getThrown
().
getMessage
()).
isEqualTo
(
"Expected"
);
assertThat
(
testThread
.
getThrown
().
getMessage
()).
isEqualTo
(
"Expected"
);
}
}
@Test
public
void
preventsNonZeroExitCodeWhenAllOtherThreadsAreDaemonThreads
()
{
try
{
SilentExitExceptionHandler
.
exitCurrentThread
();
}
catch
(
Exception
ex
)
{
TestSilentExitExceptionHandler
silentExitExceptionHandler
=
new
TestSilentExitExceptionHandler
();
silentExitExceptionHandler
.
uncaughtException
(
Thread
.
currentThread
(),
ex
);
try
{
assertThat
(
silentExitExceptionHandler
.
nonZeroExitCodePrevented
).
isTrue
();
}
finally
{
silentExitExceptionHandler
.
cleanUp
();
}
}
}
private
static
abstract
class
TestThread
extends
Thread
{
private
static
abstract
class
TestThread
extends
Thread
{
private
Throwable
thrown
;
private
Throwable
thrown
;
...
@@ -79,4 +99,58 @@ public class SilentExitExceptionHandlerTests {
...
@@ -79,4 +99,58 @@ public class SilentExitExceptionHandlerTests {
}
}
private
static
class
TestSilentExitExceptionHandler
extends
SilentExitExceptionHandler
{
private
boolean
nonZeroExitCodePrevented
;
private
final
Object
monitor
=
new
Object
();
TestSilentExitExceptionHandler
()
{
super
(
null
);
}
@Override
protected
void
preventNonZeroExitCode
()
{
this
.
nonZeroExitCodePrevented
=
true
;
}
@Override
protected
Thread
[]
getAllThreads
()
{
final
CountDownLatch
threadRunning
=
new
CountDownLatch
(
1
);
Thread
daemonThread
=
new
Thread
(
new
Runnable
()
{
@Override
public
void
run
()
{
synchronized
(
TestSilentExitExceptionHandler
.
this
.
monitor
)
{
threadRunning
.
countDown
();
try
{
TestSilentExitExceptionHandler
.
this
.
monitor
.
wait
();
}
catch
(
InterruptedException
ex
)
{
Thread
.
currentThread
().
interrupt
();
}
}
}
});
daemonThread
.
setDaemon
(
true
);
daemonThread
.
start
();
try
{
threadRunning
.
await
();
}
catch
(
InterruptedException
ex
)
{
Thread
.
currentThread
().
interrupt
();
}
return
new
Thread
[]
{
Thread
.
currentThread
(),
daemonThread
};
}
private
void
cleanUp
()
{
synchronized
(
this
.
monitor
)
{
this
.
monitor
.
notifyAll
();
}
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment