-
Notifications
You must be signed in to change notification settings - Fork 593
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide a deep config copy from ConfigHelper.use() #701
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,4 +50,35 @@ class MapUtilsTest { | |
MapUtils.traverse(m, { s -> (s.startsWith('x')) ? "replaced" : s}) | ||
assert m == [a: 'replaced', m: [b: 'replaced', c: 'otherString']] | ||
} | ||
|
||
@Test | ||
void testDeepCopy() { | ||
|
||
List l = ['a', 'b', 'c'] | ||
|
||
def original = [ | ||
list: l, | ||
set: (Set)['1', '2'], | ||
nextLevel: [ | ||
list: ['x', 'y'], | ||
duplicate: l, | ||
set: (Set)[9, 8, 7] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this would also work here. So we have several options to get a Set here rather than a list. |
||
] | ||
] | ||
|
||
def copy = MapUtils.deepCopy(original) | ||
|
||
assert ! copy.is(original) | ||
assert ! copy.list.is(original.list) | ||
assert ! copy.set.is(original.set) | ||
assert ! copy.nextLevel.list.is(original.nextLevel.list) | ||
assert ! copy.nextLevel.set.is(original.nextLevel.set) | ||
assert ! copy.nextLevel.duplicate.is(original.nextLevel.duplicate) | ||
|
||
// Within the original identical list is used twice, but the | ||
// assuption is that there are different lists in the copy. | ||
assert ! copy.nextLevel.duplicate.is(copy.list) | ||
|
||
assert copy == original | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which types do we here in practice?
I would expect numbers and Strings. Both are to my knownledge immutable (so no problem).
However, can we codify this assumption and fail if it is violated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding the types there is a description available on that site: http://groovy-lang.org/json.html.
We have to deal with:
java.lang.String
java.lang.BigDecimal
,java.lang.Integer
java.lang.Boolean
, maybe the corresponding primitivejava.util.Date
java.util.LinkedHashMap
andjava.util.ArrayList
The only issue we have wrt immutability is the
Date
. Currently we do not use this type in our config.That a good approach. In the "sister" pull request #642 we have already such a type check. Since
Date
is not used up to now this type is omitted there. I will introduce this check also here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First I though that would in principle a good idea. In the meantime I played around with it and now I think we are in a better shape when we do not enforce immutability here.
Another question is: should the default config be immutable. IMO the answer to that question is: it should be immutable. But for that we have PR #642, which is not superseded by this PR here.
With this PR we ensure that the collections and the maps are copied (... deep). These collections are not imutable (... if they would some code manipulating the config map would not not work anymore), so we do not focus on immutability here for the maps and the collections.
In the test cases we have also examples where we hand-over instances into the steps which are mutable (basically mocks for e.g. utils). But I can also imagine use-cases where this is reasonable for real-world use cases.
@benhei : having this in mind you might re-think about the proposal of ensuring immutability for the types contained in the maps/collections. Again: the default configs immutability is addressed by #642.
An example how dealing with immutable values contained somewhere in the config might look like is provided by marcusholl#4. But as outlined above I would like to suggest not to go this way.
Other question (should be IMO handled in another PR in case we would like to have this): How should we deal with the parameters handed over via step-signature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we have a miss-understanding here. My question was whether we can ensure the contract "either a object is mutable and is copied or its immutable". Lets discuss tomorrow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@benhei : I checked the details.
we have to deal with the following mutable classes when running the tests (each occurance decorated by me with a comment explaining more details):
So we have real use cases where we can hand over (via signature) mutable instances. I cannot say much about the whitesource, but in general I can think about reasonable cases. Regarding the enums: to me it looks like there is nothing wrong with providing enums via signature. This is better than strings. And enums are not immutabe by default. I mean most enums in reality will be imutable, but there is no contract requiring that ...
I will add comments to the corresponding methods creating defensive copies or the
Map
s/Collection
s saying that only theMap
s/Collection
s are copied.That is not a perfect solution, but it helps us for the problems we see currently.