Skip to content

Commit 8e02d27

Browse files
committed
Merge branch '5.2.x'
2 parents 882668c + 2c9e794 commit 8e02d27

File tree

3 files changed

+106
-13
lines changed

3 files changed

+106
-13
lines changed

spring-core/src/main/java/org/springframework/core/env/Profiles.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 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.
@@ -26,6 +26,7 @@
2626
* {@link #of(String...) of(...)} factory method.
2727
*
2828
* @author Phillip Webb
29+
* @author Sam Brannen
2930
* @since 5.1
3031
*/
3132
@FunctionalInterface
@@ -34,7 +35,7 @@ public interface Profiles {
3435
/**
3536
* Test if this {@code Profiles} instance <em>matches</em> against the given
3637
* active profiles predicate.
37-
* @param activeProfiles predicate that tests whether a given profile is
38+
* @param activeProfiles a predicate that tests whether a given profile is
3839
* currently active
3940
*/
4041
boolean matches(Predicate<String> activeProfiles);
@@ -49,16 +50,20 @@ public interface Profiles {
4950
* {@code "production"}) or a profile expression. A profile expression allows
5051
* for more complicated profile logic to be expressed, for example
5152
* {@code "production & cloud"}.
52-
* <p>The following operators are supported in profile expressions:
53+
* <p>The following operators are supported in profile expressions.
5354
* <ul>
54-
* <li>{@code !} - A logical <em>not</em> of the profile</li>
55-
* <li>{@code &} - A logical <em>and</em> of the profiles</li>
56-
* <li>{@code |} - A logical <em>or</em> of the profiles</li>
55+
* <li>{@code !} - A logical <em>NOT</em> of the profile or profile expression</li>
56+
* <li>{@code &} - A logical <em>AND</em> of the profiles or profile expressions</li>
57+
* <li>{@code |} - A logical <em>OR</em> of the profiles or profile expressions</li>
5758
* </ul>
5859
* <p>Please note that the {@code &} and {@code |} operators may not be mixed
5960
* without using parentheses. For example {@code "a & b | c"} is not a valid
6061
* expression; it must be expressed as {@code "(a & b) | c"} or
6162
* {@code "a & (b | c)"}.
63+
* <p>As of Spring Framework 5.1.17, two {@code Profiles} instances returned
64+
* by this method are considered equivalent to each other (in terms of
65+
* {@code equals()} and {@code hashCode()} semantics) if they are created
66+
* with identical <em>profile strings</em>.
6267
* @param profiles the <em>profile strings</em> to include
6368
* @return a new {@link Profiles} instance
6469
*/

spring-core/src/main/java/org/springframework/core/env/ProfilesParser.java

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 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.
@@ -18,7 +18,10 @@
1818

1919
import java.util.ArrayList;
2020
import java.util.Arrays;
21+
import java.util.Collections;
22+
import java.util.LinkedHashSet;
2123
import java.util.List;
24+
import java.util.Set;
2225
import java.util.StringTokenizer;
2326
import java.util.function.Predicate;
2427

@@ -30,6 +33,7 @@
3033
* Internal parser used by {@link Profiles#of}.
3134
*
3235
* @author Phillip Webb
36+
* @author Sam Brannen
3337
* @since 5.1
3438
*/
3539
final class ProfilesParser {
@@ -56,6 +60,7 @@ private static Profiles parseExpression(String expression) {
5660
private static Profiles parseTokens(String expression, StringTokenizer tokens) {
5761
return parseTokens(expression, tokens, Context.NONE);
5862
}
63+
5964
private static Profiles parseTokens(String expression, StringTokenizer tokens, Context context) {
6065
List<Profiles> elements = new ArrayList<>();
6166
Operator operator = null;
@@ -145,12 +150,12 @@ private enum Context {NONE, INVERT, BRACKET}
145150

146151
private static class ParsedProfiles implements Profiles {
147152

148-
private final String[] expressions;
153+
private final Set<String> expressions = new LinkedHashSet<>();
149154

150155
private final Profiles[] parsed;
151156

152157
ParsedProfiles(String[] expressions, Profiles[] parsed) {
153-
this.expressions = expressions;
158+
Collections.addAll(this.expressions, expressions);
154159
this.parsed = parsed;
155160
}
156161

@@ -164,10 +169,31 @@ public boolean matches(Predicate<String> activeProfiles) {
164169
return false;
165170
}
166171

172+
@Override
173+
public int hashCode() {
174+
return this.expressions.hashCode();
175+
}
176+
177+
@Override
178+
public boolean equals(Object obj) {
179+
if (this == obj) {
180+
return true;
181+
}
182+
if (obj == null) {
183+
return false;
184+
}
185+
if (getClass() != obj.getClass()) {
186+
return false;
187+
}
188+
ParsedProfiles that = (ParsedProfiles) obj;
189+
return this.expressions.equals(that.expressions);
190+
}
191+
167192
@Override
168193
public String toString() {
169-
return StringUtils.arrayToDelimitedString(this.expressions, " or ");
194+
return StringUtils.collectionToDelimitedString(this.expressions, " or ");
170195
}
196+
171197
}
172198

173199
}

spring-core/src/test/java/org/springframework/core/env/ProfilesTests.java

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 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.
@@ -288,10 +288,72 @@ void malformedExpressions() {
288288

289289
@Test
290290
void sensibleToString() {
291-
assertThat(Profiles.of("spring & framework", "java | kotlin").toString()).isEqualTo("spring & framework or java | kotlin");
291+
assertThat(Profiles.of("spring")).hasToString("spring");
292+
assertThat(Profiles.of("(spring & framework) | (spring & java)")).hasToString("(spring & framework) | (spring & java)");
293+
assertThat(Profiles.of("(spring&framework)|(spring&java)")).hasToString("(spring&framework)|(spring&java)");
294+
assertThat(Profiles.of("spring & framework", "java | kotlin")).hasToString("spring & framework or java | kotlin");
295+
assertThat(Profiles.of("java | kotlin", "spring & framework")).hasToString("java | kotlin or spring & framework");
292296
}
293297

294-
private void assertMalformed(Supplier<Profiles> supplier) {
298+
@Test
299+
void sensibleEquals() {
300+
assertEqual("(spring & framework) | (spring & java)");
301+
assertEqual("(spring&framework)|(spring&java)");
302+
assertEqual("spring & framework", "java | kotlin");
303+
304+
// Ensure order of individual expressions does not affect equals().
305+
String expression1 = "A | B";
306+
String expression2 = "C & (D | E)";
307+
Profiles profiles1 = Profiles.of(expression1, expression2);
308+
Profiles profiles2 = Profiles.of(expression2, expression1);
309+
assertThat(profiles1).isEqualTo(profiles2);
310+
assertThat(profiles2).isEqualTo(profiles1);
311+
}
312+
313+
private void assertEqual(String... expressions) {
314+
Profiles profiles1 = Profiles.of(expressions);
315+
Profiles profiles2 = Profiles.of(expressions);
316+
assertThat(profiles1).isEqualTo(profiles2);
317+
assertThat(profiles2).isEqualTo(profiles1);
318+
}
319+
320+
@Test
321+
void sensibleHashCode() {
322+
assertHashCode("(spring & framework) | (spring & java)");
323+
assertHashCode("(spring&framework)|(spring&java)");
324+
assertHashCode("spring & framework", "java | kotlin");
325+
326+
// Ensure order of individual expressions does not affect hashCode().
327+
String expression1 = "A | B";
328+
String expression2 = "C & (D | E)";
329+
Profiles profiles1 = Profiles.of(expression1, expression2);
330+
Profiles profiles2 = Profiles.of(expression2, expression1);
331+
assertThat(profiles1).hasSameHashCodeAs(profiles2);
332+
}
333+
334+
private void assertHashCode(String... expressions) {
335+
Profiles profiles1 = Profiles.of(expressions);
336+
Profiles profiles2 = Profiles.of(expressions);
337+
assertThat(profiles1).hasSameHashCodeAs(profiles2);
338+
}
339+
340+
@Test
341+
void equalsAndHashCodeAreNotBasedOnLogicalStructureOfNodesWithinExpressionTree() {
342+
Profiles profiles1 = Profiles.of("A | B");
343+
Profiles profiles2 = Profiles.of("B | A");
344+
345+
assertThat(profiles1.matches(activeProfiles("A"))).isTrue();
346+
assertThat(profiles1.matches(activeProfiles("B"))).isTrue();
347+
assertThat(profiles2.matches(activeProfiles("A"))).isTrue();
348+
assertThat(profiles2.matches(activeProfiles("B"))).isTrue();
349+
350+
assertThat(profiles1).isNotEqualTo(profiles2);
351+
assertThat(profiles2).isNotEqualTo(profiles1);
352+
assertThat(profiles1.hashCode()).isNotEqualTo(profiles2.hashCode());
353+
}
354+
355+
356+
private static void assertMalformed(Supplier<Profiles> supplier) {
295357
assertThatIllegalArgumentException().isThrownBy(
296358
supplier::get)
297359
.withMessageContaining("Malformed");

0 commit comments

Comments
 (0)