Skip to content

Commit bff93a6

Browse files
committed
Fix remote DevTools restart when a previously added class is then changed
Previously, if a class was added and then changed, a restart would be triggered and things would behave as if the class had been deleted. This occurred because, when looking for additional classes that were not on the original classpath, only files that had been added were considered. The subsequent change to the class was noticed as a modified rather than an addition, resulting in the class being skipped. This commit updates the resource resolver to only ignore deleted files and consider both added files and modified files when looking for additional resources. Closes gh-14205
1 parent 6910ee6 commit bff93a6

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed

spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ClassLoaderFilesResourcePatternResolver.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ private List<Resource> getAdditionalResources(String locationPattern)
130130
for (Entry<String, ClassLoaderFile> entry : sourceFolder.getFilesEntrySet()) {
131131
String name = entry.getKey();
132132
ClassLoaderFile file = entry.getValue();
133-
if (file.getKind() == Kind.ADDED
133+
if (entry.getValue().getKind() != Kind.DELETED
134134
&& this.antPathMatcher.match(trimmedLocationPattern, name)) {
135135
URL url = new URL("reloaded", null, -1, "/" + name,
136136
new ClassLoaderFileURLStreamHandler(file));

spring-boot-tests/spring-boot-integration-tests/spring-boot-devtools-tests/src/test/java/org/springframework/boot/devtools/tests/DevToolsIntegrationTests.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,53 @@ public void createAController() throws Exception {
125125

126126
}
127127

128+
@Test
129+
public void createAControllerAndThenAddARequestMapping() throws Exception {
130+
TestRestTemplate template = new TestRestTemplate();
131+
String urlBase = "http://localhost:" + awaitServerPort();
132+
assertThat(template.getForObject(urlBase + "/one", String.class))
133+
.isEqualTo("one");
134+
assertThat(template.getForEntity(urlBase + "/two", String.class).getStatusCode())
135+
.isEqualTo(HttpStatus.NOT_FOUND);
136+
controller("com.example.ControllerTwo").withRequestMapping("two").build();
137+
assertThat(template.getForObject(urlBase + "/one", String.class))
138+
.isEqualTo("one");
139+
assertThat(template.getForObject("http://localhost:" + awaitServerPort() + "/two",
140+
String.class)).isEqualTo("two");
141+
controller("com.example.ControllerTwo").withRequestMapping("two")
142+
.withRequestMapping("three").build();
143+
assertThat(template.getForObject(
144+
"http://localhost:" + awaitServerPort() + "/three", String.class))
145+
.isEqualTo("three");
146+
}
147+
148+
@Test
149+
public void createAControllerAndThenAddARequestMappingToAnExistingController()
150+
throws Exception {
151+
TestRestTemplate template = new TestRestTemplate();
152+
String urlBase = "http://localhost:" + awaitServerPort();
153+
assertThat(template.getForObject(urlBase + "/one", String.class))
154+
.isEqualTo("one");
155+
assertThat(template.getForEntity(urlBase + "/two", String.class).getStatusCode())
156+
.isEqualTo(HttpStatus.NOT_FOUND);
157+
controller("com.example.ControllerTwo").withRequestMapping("two").build();
158+
assertThat(template.getForObject(urlBase + "/one", String.class))
159+
.isEqualTo("one");
160+
assertThat(template.getForObject("http://localhost:" + awaitServerPort() + "/two",
161+
String.class)).isEqualTo("two");
162+
controller("com.example.ControllerOne").withRequestMapping("one")
163+
.withRequestMapping("three").build();
164+
int port = awaitServerPort();
165+
assertThat(
166+
template.getForObject("http://localhost:" + port + "/one", String.class))
167+
.isEqualTo("one");
168+
assertThat(
169+
template.getForObject("http://localhost:" + port + "/two", String.class))
170+
.isEqualTo("two");
171+
assertThat(template.getForObject("http://localhost:" + port + "/three",
172+
String.class)).isEqualTo("three");
173+
}
174+
128175
@Test
129176
public void deleteAController() throws Exception {
130177
TestRestTemplate template = new TestRestTemplate();
@@ -137,6 +184,25 @@ public void deleteAController() throws Exception {
137184

138185
}
139186

187+
@Test
188+
public void createAControllerAndThenDeleteIt() throws Exception {
189+
TestRestTemplate template = new TestRestTemplate();
190+
String urlBase = "http://localhost:" + awaitServerPort();
191+
assertThat(template.getForObject(urlBase + "/one", String.class))
192+
.isEqualTo("one");
193+
assertThat(template.getForEntity(urlBase + "/two", String.class).getStatusCode())
194+
.isEqualTo(HttpStatus.NOT_FOUND);
195+
controller("com.example.ControllerTwo").withRequestMapping("two").build();
196+
assertThat(template.getForObject(urlBase + "/one", String.class))
197+
.isEqualTo("one");
198+
assertThat(template.getForObject("http://localhost:" + awaitServerPort() + "/two",
199+
String.class)).isEqualTo("two");
200+
assertThat(new File(this.launchedApplication.getClassesDirectory(),
201+
"com/example/ControllerTwo.class").delete()).isTrue();
202+
assertThat(template.getForEntity("http://localhost:" + awaitServerPort() + "/two",
203+
String.class).getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
204+
}
205+
140206
private int awaitServerPort() throws Exception {
141207
long end = System.currentTimeMillis() + 30000;
142208
while (this.serverPortFile.length() == 0) {

0 commit comments

Comments
 (0)