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
a39d351e
Commit
a39d351e
authored
Apr 11, 2016
by
Phillip Webb
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Polish profile negation in YAML sub-documents
Closes gh-4953
parent
bd010494
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
85 additions
and
102 deletions
+85
-102
spring-boot-features.adoc
spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
+5
-4
SpringProfileDocumentMatcher.java
...ringframework/boot/yaml/SpringProfileDocumentMatcher.java
+40
-52
SpringProfileDocumentMatcherTests.java
...ramework/boot/yaml/SpringProfileDocumentMatcherTests.java
+40
-46
No files found.
spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
View file @
a39d351e
...
@@ -678,10 +678,11 @@ profile, and it would have to be explicitly reset in all other profiles as neces
...
@@ -678,10 +678,11 @@ profile, and it would have to be explicitly reset in all other profiles as neces
password: weak
password: weak
----
----
Spring profiles designated using the "spring.profiles" element may optionally be
Spring profiles designated using the "spring.profiles" element may optionally be negated
negated using the {@code !} character. If both negated and non-negated profiles
using the {@code !} character. If both negated and non-negated profiles are specified for
are specified for a single document, at least one non-negated profile must match
a single document, at least one non-negated profile must match and no negated profiles
and no negated profiles may match.
may match.
[[boot-features-external-config-yaml-shortcomings]]
[[boot-features-external-config-yaml-shortcomings]]
...
...
spring-boot/src/main/java/org/springframework/boot/yaml/SpringProfileDocumentMatcher.java
View file @
a39d351e
/*
/*
* 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.
...
@@ -18,12 +18,8 @@ package org.springframework.boot.yaml;
...
@@ -18,12 +18,8 @@ package org.springframework.boot.yaml;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.LinkedHashSet
;
import
java.util.LinkedHashSet
;
import
java.util.Map
;
import
java.util.Properties
;
import
java.util.Properties
;
import
java.util.Set
;
import
org.springframework.beans.factory.config.YamlProcessor.DocumentMatcher
;
import
org.springframework.beans.factory.config.YamlProcessor.DocumentMatcher
;
import
org.springframework.beans.factory.config.YamlProcessor.MatchStatus
;
import
org.springframework.beans.factory.config.YamlProcessor.MatchStatus
;
...
@@ -39,10 +35,12 @@ import org.springframework.util.StringUtils;
...
@@ -39,10 +35,12 @@ import org.springframework.util.StringUtils;
*
*
* @author Dave Syer
* @author Dave Syer
* @author Matt Benson
* @author Matt Benson
* @author Phillip Webb
*/
*/
public
class
SpringProfileDocumentMatcher
implements
DocumentMatcher
{
public
class
SpringProfileDocumentMatcher
implements
DocumentMatcher
{
private
static
final
String
[]
DEFAULT_PROFILES
=
new
String
[]
{
"^\\s*$"
};
private
static
final
String
[]
DEFAULT_PROFILES
=
new
String
[]
{
"^\\s*$"
};
private
static
final
String
SPRING_PROFILES
=
"spring.profiles"
;
private
static
final
String
SPRING_PROFILES
=
"spring.profiles"
;
private
String
[]
activeProfiles
=
new
String
[
0
];
private
String
[]
activeProfiles
=
new
String
[
0
];
...
@@ -63,62 +61,52 @@ public class SpringProfileDocumentMatcher implements DocumentMatcher {
...
@@ -63,62 +61,52 @@ public class SpringProfileDocumentMatcher implements DocumentMatcher {
@Override
@Override
public
MatchStatus
matches
(
Properties
properties
)
{
public
MatchStatus
matches
(
Properties
properties
)
{
DocumentMatcher
activeProfilesMatcher
=
getActiveProfilesDocumentMatcher
();
String
profiles
=
properties
.
getProperty
(
SPRING_PROFILES
);
String
negative
=
extractProfiles
(
profiles
,
ProfileType
.
NEGATIVE
);
String
positive
=
extractProfiles
(
profiles
,
ProfileType
.
POSITIVE
);
if
(
StringUtils
.
hasLength
(
negative
))
{
properties
=
new
Properties
(
properties
);
properties
.
setProperty
(
SPRING_PROFILES
,
negative
);
switch
(
activeProfilesMatcher
.
matches
(
properties
))
{
case
FOUND:
return
MatchStatus
.
NOT_FOUND
;
case
NOT_FOUND:
return
MatchStatus
.
FOUND
;
}
properties
.
setProperty
(
SPRING_PROFILES
,
positive
);
}
return
activeProfilesMatcher
.
matches
(
properties
);
}
private
DocumentMatcher
getActiveProfilesDocumentMatcher
()
{
String
[]
profiles
=
this
.
activeProfiles
;
String
[]
profiles
=
this
.
activeProfiles
;
if
(
profiles
.
length
==
0
)
{
if
(
profiles
.
length
==
0
)
{
profiles
=
DEFAULT_PROFILES
;
profiles
=
DEFAULT_PROFILES
;
}
}
ArrayDocumentMatcher
next
=
new
ArrayDocumentMatcher
(
SPRING_PROFILES
,
profiles
);
return
new
ArrayDocumentMatcher
(
SPRING_PROFILES
,
profiles
);
if
(
properties
.
containsKey
(
SPRING_PROFILES
))
{
properties
=
new
Properties
(
properties
);
Map
<
Boolean
,
String
>
sortedProfiles
=
sortProfiles
(
properties
.
getProperty
(
SPRING_PROFILES
));
// handle negated profiles:
if
(
sortedProfiles
.
containsKey
(
Boolean
.
FALSE
))
{
properties
.
setProperty
(
SPRING_PROFILES
,
sortedProfiles
.
get
(
Boolean
.
FALSE
));
MatchStatus
matchStatus
=
next
.
matches
(
properties
);
switch
(
matchStatus
)
{
case
FOUND:
return
MatchStatus
.
NOT_FOUND
;
case
NOT_FOUND:
return
MatchStatus
.
FOUND
;
default
:
break
;
}
}
properties
.
setProperty
(
SPRING_PROFILES
,
sortedProfiles
.
get
(
Boolean
.
TRUE
));
}
return
next
.
matches
(
properties
);
}
}
private
Map
<
Boolean
,
String
>
sortProfiles
(
String
value
)
{
private
String
extractProfiles
(
String
profiles
,
ProfileType
type
)
{
if
(
value
.
indexOf
(
'!'
)
>=
0
)
{
if
(
profiles
==
null
)
{
Set
<
String
>
positive
=
new
HashSet
<
String
>();
return
null
;
Set
<
String
>
negative
=
new
HashSet
<
String
>();
}
for
(
String
s
:
StringUtils
.
commaDelimitedListToSet
(
value
))
{
StringBuilder
result
=
new
StringBuilder
();
if
(
s
.
charAt
(
0
)
==
'!'
)
{
for
(
String
candidate
:
StringUtils
.
commaDelimitedListToSet
(
profiles
))
{
negative
.
add
(
s
.
substring
(
1
));
ProfileType
candidateType
=
ProfileType
.
POSITIVE
;
}
if
(
candidate
.
startsWith
(
"!"
))
{
else
{
candidateType
=
ProfileType
.
NEGATIVE
;
positive
.
add
(
s
);
}
}
}
if
(!
negative
.
isEmpty
())
{
if
(
candidateType
==
type
)
{
Map
<
Boolean
,
String
>
result
=
new
HashMap
<
Boolean
,
String
>();
result
.
append
(
result
.
length
()
>
0
?
","
:
""
);
result
.
put
(
Boolean
.
FALSE
,
result
.
append
(
candidate
.
substring
(
type
==
ProfileType
.
POSITIVE
?
0
:
1
));
StringUtils
.
collectionToCommaDelimitedString
(
negative
));
if
(!
positive
.
isEmpty
())
{
result
.
put
(
Boolean
.
TRUE
,
StringUtils
.
collectionToCommaDelimitedString
(
positive
));
}
return
result
;
}
}
}
}
return
Collections
.
singletonMap
(
Boolean
.
TRUE
,
value
);
return
result
.
toString
();
}
enum
ProfileType
{
POSITIVE
,
NEGATIVE
}
}
}
}
spring-boot/src/test/java/org/springframework/boot/yaml/SpringProfileDocumentMatcherTests.java
View file @
a39d351e
...
@@ -19,13 +19,15 @@ package org.springframework.boot.yaml;
...
@@ -19,13 +19,15 @@ package org.springframework.boot.yaml;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.util.Properties
;
import
java.util.Properties
;
import
org.junit.Assert
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.springframework.beans.factory.config.YamlProcessor.DocumentMatcher
;
import
org.springframework.beans.factory.config.YamlProcessor.MatchStatus
;
import
org.springframework.beans.factory.config.YamlProcessor.MatchStatus
;
import
org.springframework.core.io.ByteArrayResource
;
import
org.springframework.core.io.ByteArrayResource
;
import
org.springframework.core.io.support.PropertiesLoaderUtils
;
import
org.springframework.core.io.support.PropertiesLoaderUtils
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
/**
/**
* Tests for {@link SpringProfileDocumentMatcher}.
* Tests for {@link SpringProfileDocumentMatcher}.
*
*
...
@@ -34,79 +36,71 @@ import org.springframework.core.io.support.PropertiesLoaderUtils;
...
@@ -34,79 +36,71 @@ import org.springframework.core.io.support.PropertiesLoaderUtils;
public
class
SpringProfileDocumentMatcherTests
{
public
class
SpringProfileDocumentMatcherTests
{
@Test
@Test
public
void
testMatchesSingleProfile
()
throws
IOException
{
public
void
matchesSingleProfile
()
throws
IOException
{
SpringProfileDocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
DocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
"bar"
);
"bar"
);
Properties
properties
=
getProperties
(
"spring.profiles: foo"
);
Assert
.
assertSame
(
MatchStatus
.
FOUND
,
assertThat
(
matcher
.
matches
(
properties
)).
isEqualTo
(
MatchStatus
.
FOUND
);
matcher
.
matches
(
getProperties
(
"spring.profiles: foo"
)));
}
}
@Test
@Test
public
void
testAbstainNoConfiguredProfiles
()
throws
IOException
{
public
void
abstainNoConfiguredProfiles
()
throws
IOException
{
SpringProfileDocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
DocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
"bar"
);
"bar"
);
Properties
properties
=
getProperties
(
"some.property: spam"
);
Assert
.
assertSame
(
MatchStatus
.
ABSTAIN
,
assertThat
(
matcher
.
matches
(
properties
)).
isEqualTo
(
MatchStatus
.
ABSTAIN
);
matcher
.
matches
(
getProperties
(
"some.property: spam"
)));
}
}
@Test
@Test
public
void
testN
oActiveProfiles
()
throws
IOException
{
public
void
n
oActiveProfiles
()
throws
IOException
{
SpringProfile
DocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
();
DocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
();
Assert
.
assertSame
(
MatchStatus
.
NOT_FOUND
,
Properties
properties
=
getProperties
(
"spring.profiles: bar,spam"
);
matcher
.
matches
(
getProperties
(
"spring.profiles: bar,spam"
))
);
assertThat
(
matcher
.
matches
(
properties
)).
isEqualTo
(
MatchStatus
.
NOT_FOUND
);
}
}
@Test
@Test
public
void
testMatchesCommaSeparatedArray
()
throws
IOException
{
public
void
matchesCommaSeparatedArray
()
throws
IOException
{
SpringProfileDocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
DocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
"bar"
);
"bar"
);
Properties
properties
=
getProperties
(
"spring.profiles: bar,spam"
);
Assert
.
assertSame
(
MatchStatus
.
FOUND
,
assertThat
(
matcher
.
matches
(
properties
)).
isEqualTo
(
MatchStatus
.
FOUND
);
matcher
.
matches
(
getProperties
(
"spring.profiles: bar,spam"
)));
}
}
@Test
@Test
public
void
testNoMatchingProfiles
()
throws
IOException
{
public
void
noMatchingProfiles
()
throws
IOException
{
SpringProfileDocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
DocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
"bar"
);
"bar"
);
Properties
properties
=
getProperties
(
"spring.profiles: baz,blah"
);
Assert
.
assertSame
(
MatchStatus
.
NOT_FOUND
,
assertThat
(
matcher
.
matches
(
properties
)).
isEqualTo
(
MatchStatus
.
NOT_FOUND
);
matcher
.
matches
(
getProperties
(
"spring.profiles: baz,blah"
)));
}
}
@Test
@Test
public
void
testInverseMatchSingle
()
throws
IOException
{
public
void
inverseMatchSingle
()
throws
IOException
{
SpringProfileDocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
DocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
"bar"
);
"bar"
);
Properties
properties
=
getProperties
(
"spring.profiles: !baz"
);
Assert
.
assertSame
(
MatchStatus
.
FOUND
,
assertThat
(
matcher
.
matches
(
properties
)).
isEqualTo
(
MatchStatus
.
FOUND
);
matcher
.
matches
(
getProperties
(
"spring.profiles: !baz"
)));
}
}
@Test
@Test
public
void
testInverseMatchMulti
()
throws
IOException
{
public
void
testInverseMatchMulti
()
throws
IOException
{
SpringProfileDocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
DocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
"bar"
);
"bar"
);
Properties
properties
=
getProperties
(
"spring.profiles: !baz,!blah"
);
Assert
.
assertSame
(
MatchStatus
.
FOUND
,
assertThat
(
matcher
.
matches
(
properties
)).
isEqualTo
(
MatchStatus
.
FOUND
);
matcher
.
matches
(
getProperties
(
"spring.profiles: !baz,!blah"
)));
}
}
@Test
@Test
public
void
testNegatedAndNonNegated
()
throws
IOException
{
public
void
negatedAndNonNegated
()
throws
IOException
{
SpringProfileDocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
DocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
"bar"
,
"blah"
);
"bar"
,
"blah"
);
Properties
properties
=
getProperties
(
"spring.profiles: !baz,blah"
);
Assert
.
assertSame
(
MatchStatus
.
FOUND
,
assertThat
(
matcher
.
matches
(
properties
)).
isEqualTo
(
MatchStatus
.
FOUND
);
matcher
.
matches
(
getProperties
(
"spring.profiles: !baz,blah"
)));
}
}
@Test
@Test
public
void
testNegatedTrumpsMatching
()
throws
IOException
{
public
void
negatedTrumpsMatching
()
throws
IOException
{
SpringProfileDocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
DocumentMatcher
matcher
=
new
SpringProfileDocumentMatcher
(
"foo"
,
"baz"
,
"blah"
);
"baz"
,
"blah"
);
Properties
properties
=
getProperties
(
"spring.profiles: !baz,blah"
);
Assert
.
assertSame
(
MatchStatus
.
NOT_FOUND
,
assertThat
(
matcher
.
matches
(
properties
)).
isEqualTo
(
MatchStatus
.
NOT_FOUND
);
matcher
.
matches
(
getProperties
(
"spring.profiles: !baz,blah"
)));
}
}
private
Properties
getProperties
(
String
values
)
throws
IOException
{
private
Properties
getProperties
(
String
values
)
throws
IOException
{
return
PropertiesLoaderUtils
ByteArrayResource
resource
=
new
ByteArrayResource
(
values
.
getBytes
());
.
loadProperties
(
new
ByteArrayResource
(
values
.
getBytes
())
);
return
PropertiesLoaderUtils
.
loadProperties
(
resource
);
}
}
}
}
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