Skip to content

Commit b102fdd

Browse files
committed
Merge branch '2.3.x' into 2.4.x
Closes gh-26738
2 parents 363c43e + 1532495 commit b102fdd

File tree

2 files changed

+107
-14
lines changed

2 files changed

+107
-14
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/RandomValuePropertySource.java

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 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.
@@ -16,8 +16,13 @@
1616

1717
package org.springframework.boot.env;
1818

19+
import java.util.OptionalInt;
20+
import java.util.OptionalLong;
1921
import java.util.Random;
2022
import java.util.UUID;
23+
import java.util.function.BiPredicate;
24+
import java.util.function.Function;
25+
import java.util.function.Predicate;
2126

2227
import org.apache.commons.logging.Log;
2328
import org.apache.commons.logging.LogFactory;
@@ -27,6 +32,7 @@
2732
import org.springframework.core.env.PropertySource;
2833
import org.springframework.core.env.StandardEnvironment;
2934
import org.springframework.core.log.LogMessage;
35+
import org.springframework.util.Assert;
3036
import org.springframework.util.DigestUtils;
3137
import org.springframework.util.StringUtils;
3238

@@ -46,11 +52,13 @@
4652
* suffix whose syntax is:
4753
* <p>
4854
* {@code OPEN value (,max) CLOSE} where the {@code OPEN,CLOSE} are any character and
49-
* {@code value,max} are integers. If {@code max} is provided then {@code value} is the
50-
* minimum value and {@code max} is the maximum (exclusive).
55+
* {@code value,max} are integers. If {@code max} is not provided, then 0 is used as the
56+
* lower bound and {@code value} is the upper bound. If {@code max} is provided then
57+
* {@code value} is the minimum value and {@code max} is the maximum (exclusive).
5158
*
5259
* @author Dave Syer
5360
* @author Matt Benson
61+
* @author Madhura Bhave
5462
* @since 1.0.0
5563
*/
5664
public class RandomValuePropertySource extends PropertySource<Random> {
@@ -113,22 +121,21 @@ private String getRange(String type, String prefix) {
113121
}
114122

115123
private int getNextIntInRange(String range) {
116-
String[] tokens = StringUtils.commaDelimitedListToStringArray(range);
117-
int start = Integer.parseInt(tokens[0]);
118-
if (tokens.length == 1) {
119-
return getSource().nextInt(start);
124+
Range<Integer> intRange = Range.get(range, Integer::parseInt, (t) -> t > 0, 0, (t1, t2) -> t1 < t2);
125+
OptionalInt first = getSource().ints(1, intRange.getMin(), intRange.getMax()).findFirst();
126+
if (!first.isPresent()) {
127+
throw new RuntimeException("Could not get random number for range '" + range + "'");
120128
}
121-
return start + getSource().nextInt(Integer.parseInt(tokens[1]) - start);
129+
return first.getAsInt();
122130
}
123131

124132
private long getNextLongInRange(String range) {
125-
String[] tokens = StringUtils.commaDelimitedListToStringArray(range);
126-
if (tokens.length == 1) {
127-
return Math.abs(getSource().nextLong() % Long.parseLong(tokens[0]));
133+
Range<Long> longRange = Range.get(range, Long::parseLong, (t) -> t > 0L, 0L, (t1, t2) -> t1 < t2);
134+
OptionalLong first = getSource().longs(1, longRange.getMin(), longRange.getMax()).findFirst();
135+
if (!first.isPresent()) {
136+
throw new RuntimeException("Could not get random number for range '" + range + "'");
128137
}
129-
long lowerBound = Long.parseLong(tokens[0]);
130-
long upperBound = Long.parseLong(tokens[1]) - lowerBound;
131-
return lowerBound + Math.abs(getSource().nextLong() % upperBound);
138+
return first.getAsLong();
132139
}
133140

134141
private Object getRandomBytes() {
@@ -158,4 +165,39 @@ static void addToEnvironment(ConfigurableEnvironment environment, Log logger) {
158165
logger.trace("RandomValuePropertySource add to Environment");
159166
}
160167

168+
static final class Range<T extends Number> {
169+
170+
private final T min;
171+
172+
private final T max;
173+
174+
private Range(T min, T max) {
175+
this.min = min;
176+
this.max = max;
177+
178+
}
179+
180+
static <T extends Number> Range<T> get(String range, Function<String, T> parse, Predicate<T> boundValidator,
181+
T defaultMin, BiPredicate<T, T> rangeValidator) {
182+
String[] tokens = StringUtils.commaDelimitedListToStringArray(range);
183+
T token1 = parse.apply(tokens[0]);
184+
if (tokens.length == 1) {
185+
Assert.isTrue(boundValidator.test(token1), "Bound must be positive.");
186+
return new Range<>(defaultMin, token1);
187+
}
188+
T token2 = parse.apply(tokens[1]);
189+
Assert.isTrue(rangeValidator.test(token1, token2), "Lower bound must be less than upper bound.");
190+
return new Range<>(token1, token2);
191+
}
192+
193+
T getMin() {
194+
return this.min;
195+
}
196+
197+
T getMax() {
198+
return this.max;
199+
}
200+
201+
}
202+
161203
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/RandomValuePropertySourceTests.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.mock.env.MockEnvironment;
2929

3030
import static org.assertj.core.api.Assertions.assertThat;
31+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
3132
import static org.mockito.BDDMockito.given;
3233
import static org.mockito.Mockito.spy;
3334

@@ -72,12 +73,37 @@ void getPropertyWhenIntRangeReturnsValue() {
7273
assertThat(value < 10).isTrue();
7374
}
7475

76+
@Test
77+
void intRangeWhenLowerBoundEqualsUpperBoundShouldFailWithIllegalArgumentException() {
78+
assertThatIllegalArgumentException().isThrownBy(() -> this.source.getProperty("random.int[4,4]"))
79+
.withMessage("Lower bound must be less than upper bound.");
80+
}
81+
82+
@Test
83+
void intRangeWhenLowerBoundNegative() {
84+
Integer value = (Integer) this.source.getProperty("random.int[-4,4]");
85+
assertThat(value >= -4).isTrue();
86+
assertThat(value < 4).isTrue();
87+
}
88+
7589
@Test
7690
void getPropertyWhenIntMaxReturnsValue() {
7791
Integer value = (Integer) this.source.getProperty("random.int(10)");
7892
assertThat(value).isNotNull().isLessThan(10);
7993
}
8094

95+
@Test
96+
void intMaxZero() {
97+
assertThatIllegalArgumentException().isThrownBy(() -> this.source.getProperty("random.int(0)"))
98+
.withMessage("Bound must be positive.");
99+
}
100+
101+
@Test
102+
void intNegativeBound() {
103+
assertThatIllegalArgumentException().isThrownBy(() -> this.source.getProperty("random.int(-5)"))
104+
.withMessage("Bound must be positive.");
105+
}
106+
81107
@Test
82108
void getPropertyWhenLongReturnsValue() {
83109
Long value = (Long) this.source.getProperty("random.long");
@@ -90,12 +116,37 @@ void getPropertyWhenLongRangeReturnsValue() {
90116
assertThat(value).isNotNull().isBetween(4L, 10L);
91117
}
92118

119+
@Test
120+
void longRangeWhenLowerBoundEqualsUpperBoundShouldFailWithIllegalArgumentException() {
121+
assertThatIllegalArgumentException().isThrownBy(() -> this.source.getProperty("random.long[4,4]"))
122+
.withMessage("Lower bound must be less than upper bound.");
123+
}
124+
125+
@Test
126+
void longRangeWhenLowerBoundNegativeShouldFailWithIllegalArgumentException() {
127+
Long value = (Long) this.source.getProperty("random.long[-4,4]");
128+
assertThat(value >= -4).isTrue();
129+
assertThat(value < 4).isTrue();
130+
}
131+
93132
@Test
94133
void getPropertyWhenLongMaxReturnsValue() {
95134
Long value = (Long) this.source.getProperty("random.long(10)");
96135
assertThat(value).isNotNull().isLessThan(10L);
97136
}
98137

138+
@Test
139+
void longMaxZero() {
140+
assertThatIllegalArgumentException().isThrownBy(() -> this.source.getProperty("random.long(0)"))
141+
.withMessage("Bound must be positive.");
142+
}
143+
144+
@Test
145+
void longNegativeBound() {
146+
assertThatIllegalArgumentException().isThrownBy(() -> this.source.getProperty("random.long(-5)"))
147+
.withMessage("Bound must be positive.");
148+
}
149+
99150
@Test
100151
void getPropertyWhenLongOverflowReturnsValue() {
101152
RandomValuePropertySource source = spy(this.source);

0 commit comments

Comments
 (0)