Skip to content

Commit 66d1f5c

Browse files
committed
Fix expansion of static-locations array
This commit fixes a NPE when the static-locations array of `ResourceProperties` has to be expanded as the setter is cleaning the values of the array and is affected by a non-intuitive behaviour of the binder. When the binder needs to set an element of an array and the size of the array isn't large enough, the binder proceeds as follows: * An array of the required size is created * The content of the original array is copied over * The setter of the property is invoked with the new array * The setter of the property is invoked and the returned array is mutated to set the requested value While one would expect the array to contain the requested value when the setter is invoked, this is not the case. Also, the array might contain null values if a value at index 8 should be set and the array has a size of 3. All in all, `ResourceProperties#appendSlashIfNecessary` has to account for `null` and an additional round of cleaning has to happen once binding has completed. Closes gh-12360
1 parent 758dca5 commit 66d1f5c

File tree

2 files changed

+85
-3
lines changed

2 files changed

+85
-3
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ResourceProperties.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
2020
import java.util.Collections;
2121
import java.util.List;
2222

23+
import org.springframework.beans.factory.InitializingBean;
2324
import org.springframework.boot.context.properties.ConfigurationProperties;
2425
import org.springframework.boot.context.properties.NestedConfigurationProperty;
2526
import org.springframework.context.ResourceLoaderAware;
@@ -37,7 +38,7 @@
3738
* @since 1.1.0
3839
*/
3940
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
40-
public class ResourceProperties implements ResourceLoaderAware {
41+
public class ResourceProperties implements ResourceLoaderAware, InitializingBean {
4142

4243
private static final String[] SERVLET_RESOURCE_LOCATIONS = { "/" };
4344

@@ -81,6 +82,11 @@ public void setResourceLoader(ResourceLoader resourceLoader) {
8182
this.resourceLoader = resourceLoader;
8283
}
8384

85+
@Override
86+
public void afterPropertiesSet() {
87+
this.staticLocations = appendSlashIfNecessary(this.staticLocations);
88+
}
89+
8490
public String[] getStaticLocations() {
8591
return this.staticLocations;
8692
}
@@ -93,7 +99,9 @@ private String[] appendSlashIfNecessary(String[] staticLocations) {
9399
String[] normalized = new String[staticLocations.length];
94100
for (int i = 0; i < staticLocations.length; i++) {
95101
String location = staticLocations[i];
96-
normalized[i] = (location.endsWith("/") ? location : location + "/");
102+
if (location != null) {
103+
normalized[i] = (location.endsWith("/") ? location : location + "/");
104+
}
97105
}
98106
return normalized;
99107
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.web;
18+
19+
import org.junit.After;
20+
import org.junit.Test;
21+
22+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
23+
import org.springframework.boot.test.util.EnvironmentTestUtils;
24+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
25+
import org.springframework.context.annotation.Configuration;
26+
27+
import static org.assertj.core.api.Assertions.assertThat;
28+
29+
/**
30+
* Binding tests for {@link ResourceProperties}.
31+
*
32+
* @author Stephane Nicoll
33+
*/
34+
public class ResourcePropertiesBindingTests {
35+
36+
private AnnotationConfigApplicationContext context;
37+
38+
@After
39+
public void close() {
40+
if (this.context != null) {
41+
this.context.close();
42+
}
43+
}
44+
45+
@Test
46+
public void staticLocationsExpandArray() {
47+
ResourceProperties properties = load(
48+
"spring.resources.static-locations[0]=classpath:/one/",
49+
"spring.resources.static-locations[1]=classpath:/two",
50+
"spring.resources.static-locations[2]=classpath:/three/",
51+
"spring.resources.static-locations[3]=classpath:/four",
52+
"spring.resources.static-locations[4]=classpath:/five/",
53+
"spring.resources.static-locations[5]=classpath:/six");
54+
assertThat(properties.getStaticLocations()).contains("classpath:/one/",
55+
"classpath:/two/", "classpath:/three/", "classpath:/four/",
56+
"classpath:/five/", "classpath:/six/");
57+
}
58+
59+
private ResourceProperties load(String... environment) {
60+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
61+
EnvironmentTestUtils.addEnvironment(ctx, environment);
62+
ctx.register(TestConfiguration.class);
63+
ctx.refresh();
64+
this.context = ctx;
65+
return this.context.getBean(ResourceProperties.class);
66+
}
67+
68+
@Configuration
69+
@EnableConfigurationProperties(ResourceProperties.class)
70+
static class TestConfiguration {
71+
72+
}
73+
74+
}

0 commit comments

Comments
 (0)