-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Support custom body patterns and rework content pattern deserialization. #2592
base: master
Are you sure you want to change the base?
Conversation
6c82031
to
8adf840
Compare
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.
The changes represented in AdminApiTest
are a change in behavior allowing any value that can be converted to String, not just TextNode
s.
src/main/java/com/github/tomakehurst/wiremock/matching/ContentPatternDeserialiser.java
Outdated
Show resolved
Hide resolved
@tomakehurst, I see you self-assigned this. I was curious if you had any thoughts on this PR. My main motivation is for improving wiremock-graphql-extension to expose a reusable EqualToGraphqlPattern. |
It's a change I'd definitely like to make, but reviewing a 31 file PR requires a level of uninterrupted focus I'm not not getting much of at the moment. Also the priority is sorting out this Jetty 12 compatibility issue as nearly everyone using Spring is complaining about it. After that's shipped I should be able to take a proper look at this. |
} | ||
|
||
public static void registerPatterns(Map<String, Class<? extends ContentPattern<?>>> patterns) { | ||
patterns.forEach(PATTERNS::putIfAbsent); |
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.
The issue with this approach is when there are multiple WM instances running in the same JVM. Most of the time it'll probably be fine, but produce weird edge cases when not.
So far we've kept global static state out of WireMock for precisely this reason and I'd be reluctant to start introducing it here.
From my analysis a while back, there are 2 other approaches that could be made to work per-instance:
- Make
Json
a service that's injected everywhere it's needed, then custom serializers can be attached to theObjectMapper
it wraps. This would be the cleanest way to do it but is a pretty large amount of work. - Deserialize unknown matcher keys into a
Map
(e.g. via Jackson's@JsonAnySetter
/@JsonAnyGetter
) then later associate them with matcher extensions that have been registered.
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 have just pushed some code for another option:
3. Use thread local state instead of global static state. Before performing any operations that deserializes a StubMapping
or StubMappingCollection
, use the Extensions
of the currently running WM instance to supply ContentPatternDeserialiser
with the extensions that have been registered.
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.
- Seems too complex of a change.
- I may spend some time looking at this option, but I think it will look a lot like my current code. Where I make changes in the locations that deserialize
StubMapping
andStubMappingCollection
, but instead of tampering withContentPatternDeserialiser
, I would post process the object to create concrete stub mappings from the generic map.
8adf840
to
2d118dc
Compare
Hey, sorry for taking so long to review this. I think this is an improvement over having to live with shared/static state, I still have a "there be dragons" feeling about using thread locals on this way, based on repeated previous experiences of edge cases, hard-to-debug problems and difficulty setting up tests correctly. I do have an idea derived from yours that could get us to a better place however: modify the |
2d118dc
to
226f817
Compare
I have one more simple idea I would love for you to review when you have the time (just look at second commit as first is largely unchanged). This approach will attempt to use the built-in patterns first, but will then fall back to looking for a Pros:
Cons:
Example: {
"class": "a.b.c.CustomStringValuePattern",
"customStringValue": "a",
"additionalProperty": "b"
} @JsonDeserialize
public class CustomStringValuePattern extends StringValuePattern {
@JsonCreator
public CustomStringValuePattern(@JsonProperty("customStringValue") String customStringValue, @JsonProperty("additionalProperty") String additonalProperty) {
super(customStringValue);
}
@Override
public MatchResult match(String value) {
return MatchResult.of(false); // TODO
}
} |
I'm not really keen on this idea I'm afraid, as it means a) (as you say) there'd be two ways to add extensions, b) it wouldn't be possible to inject WireMock services or otherwise define your own construction logic. |
416a93e
to
2f2d96d
Compare
42f0c7d
to
6bf5d64
Compare
6bf5d64
to
dee9583
Compare
Thanks @tomakehurst for your patience with this PR. Currently running into issue around
|
Allow users to define
ContentPatternExtension
s to support custom body patterns.Extensions
will register them against theContentPatternDeserializer
to allow theContentPattern
(orStringValuePattern
) subclasses to be supplied via json mapping files.In order to allow these new
ContentPatterns
to support an arbitrary number and variety of parameters theContentPatternDeserialiser
was modified to simply identify the appropriate class and delegate to the@JsonCreator
of that class.This is superior to using custom-matching:
bodyPatterns
are able to be supplied whereas only a singlecustomMatcher
can be supplied.StringValuePattern
has more reusability with other components (e.g.matchesJsonPath
,matchesXPath
,and
,or
,not
, etc.)References
Submitter checklist
#help-contributing
or a project-specific channel like#wiremock-java