Skip to content
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

Multiple versions of org.springframework:spring-web:jar, leading to inconsistent semantic behaviors #1143

Closed
HelloCoCooo opened this issue Mar 3, 2019 · 3 comments

Comments

@HelloCoCooo
Copy link
Contributor

HelloCoCooo commented Mar 3, 2019

Hi, there are multiple versions of org.springframework:spring-web:jar in rest-assured-3.3.0. As shown in the following dependency tree, according to Maven's dependency management strategy, only org.springframework:spring-web:jar:4.2.6.RELEASE can be loaded, and org.springframework:spring-web:jar:4.3.19.RELEASE will be shadowed.

The following risky methods included in the shadowed version org.springframework:spring-web:jar:4.3.19.RELEASE are referenced by your project, but these methods are missing in the actual loaded version org.springframework:spring-web:jar:4.2.6.RELEASE. Surprisingly, it will not cause NoSuchMethodError at rumtime.

Risky method list:
<org.springframework.http.converter.json.SpringHandlerInstantiator.namingStrategyInstance(MapperConfig, Annotated, java.lang.Class)>

<org.springframework.http.converter.json.SpringHandlerInstantiator.virtualPropertyWriterInstance(MapperConfig, java.lang.Class)>

<org.springframework.http.converter.json.SpringHandlerInstantiator.converterInstance(MapperConfig, Annotated, java.lang.Class)>

<org.springframework.http.converter.json.SpringHandlerInstantiator.valueInstantiatorInstance(MapperConfig, Annotated, java.lang.Class)>

<org.springframework.http.converter.json.SpringHandlerInstantiator.resolverIdGeneratorInstance(MapperConfig, Annotated, java.lang.Class)>

<org.springframework.http.converter.json.SpringHandlerInstantiator.objectIdGeneratorInstance(MapperConfig, Annotated, java.lang.Class)>

For instance, method <org.springframework.http.converter.json.SpringHandlerInstantiator.namingStrategyInstance(MapperConfig, Annotated, java.lang.Class)> is invoked via the following expected path:

<org.springframework.security.web.firewall.StrictHttpFirewall: void setAllowBackSlash(boolean)> C:\Users\Flipped\.m2\repository\org\springframework\security\spring-security-web\4.2.9.RELEASE\spring-security-web-4.2.9.RELEASE.jar
<org.springframework.security.web.firewall.StrictHttpFirewall: void urlBlacklistsAddAll(java.util.Collection)> C:\Users\Flipped\.m2\repository\org\springframework\security\spring-security-web\4.2.9.RELEASE\spring-security-web-4.2.9.RELEASE.jar
<groovy.util.ObservableSet: boolean addAll(java.util.Collection)> C:\Users\Flipped\.m2\repository\org\codehaus\groovy\groovy\2.4.15\groovy-2.4.15.jar
<com.fasterxml.jackson.databind.MappingIterator: java.lang.Object next()> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.MappingIterator: java.lang.Object nextValue()> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.deser.std.ReferenceTypeDeserializer: java.lang.Object deserialize(com.fasterxml.jackson.core.JsonParser,com.fasterxml.jackson.databind.DeserializationContext)> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.deser.BeanDeserializerBase: java.lang.Object deserializeWithType(com.fasterxml.jackson.core.JsonParser,com.fasterxml.jackson.databind.DeserializationContext,com.fasterxml.jackson.databind.jsontype.TypeDeserializer)> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer: java.lang.Object deserializeTypedFromObject(com.fasterxml.jackson.core.JsonParser,com.fasterxml.jackson.databind.DeserializationContext)> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer: java.lang.Object _deserializeTypedUsingDefaultImpl(com.fasterxml.jackson.core.JsonParser,com.fasterxml.jackson.databind.DeserializationContext,com.fasterxml.jackson.databind.util.TokenBuffer)> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.DeserializationContext: com.fasterxml.jackson.databind.JsonDeserializer findContextualValueDeserializer(com.fasterxml.jackson.databind.JavaType,com.fasterxml.jackson.databind.BeanProperty)> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.DeserializationContext: com.fasterxml.jackson.databind.JsonDeserializer handleSecondaryContextualization(com.fasterxml.jackson.databind.JsonDeserializer,com.fasterxml.jackson.databind.BeanProperty,com.fasterxml.jackson.databind.JavaType)> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.deser.std.MapEntryDeserializer: com.fasterxml.jackson.databind.JsonDeserializer createContextual(com.fasterxml.jackson.databind.DeserializationContext,com.fasterxml.jackson.databind.BeanProperty)> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.DeserializationContext: com.fasterxml.jackson.databind.KeyDeserializer findKeyDeserializer(com.fasterxml.jackson.databind.JavaType,com.fasterxml.jackson.databind.BeanProperty)> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.deser.DeserializerCache: com.fasterxml.jackson.databind.KeyDeserializer findKeyDeserializer(com.fasterxml.jackson.databind.DeserializationContext,com.fasterxml.jackson.databind.deser.DeserializerFactory,com.fasterxml.jackson.databind.JavaType)> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.deser.BasicDeserializerFactory: com.fasterxml.jackson.databind.KeyDeserializer createKeyDeserializer(com.fasterxml.jackson.databind.DeserializationContext,com.fasterxml.jackson.databind.JavaType)> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.deser.BasicDeserializerFactory: com.fasterxml.jackson.databind.KeyDeserializer _createEnumKeyDeserializer(com.fasterxml.jackson.databind.DeserializationContext,com.fasterxml.jackson.databind.JavaType)> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.introspect.BasicBeanDescription: com.fasterxml.jackson.databind.introspect.AnnotatedMember findJsonValueAccessor()> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector: com.fasterxml.jackson.databind.introspect.AnnotatedMember getJsonValueAccessor()> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector: void collectAll()> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector: com.fasterxml.jackson.databind.PropertyNamingStrategy _findNamingStrategy()> C:\Users\Flipped\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.7\jackson-databind-2.9.7.jar
<org.springframework.http.converter.json.SpringHandlerInstantiator: com.fasterxml.jackson.databind.PropertyNamingStrategy namingStrategyInstance(com.fasterxml.jackson.databind.cfg.MapperConfig,com.fasterxml.jackson.databind.introspect.Annotated,java.lang.Class)>

By further analyzing, I found that the caller belonging to rest-assured-3.3.0 would invoke the methods HandlerInstantiator.namingStrategyInstance(...), HandlerInstantiator.virtualPropertyWriterInstance(...), HandlerInstantiator.converterInstance(...), HandlerInstantiator.valueInstantiatorInstance(...), HandlerInstantiator.resolverIdGeneratorInstance(...), HandlerInstantiator.objectIdGeneratorInstance(...) defined in the superclass of SpringHandlerInstantiator (SpringHandlerInstantiator extends HandlerInstantiator) with the same signature of the expected callee, due to dynamic binding mechanism.

Although the actual invoked methods belonging to HandlerInstantiator has the same method names, same parameter types and return types as the expected methods defined in its subclass SpringHandlerInstantiator, but they has different control flows and different behaviors. Maybe it is buggy behavior.

Solution:

Use the newer version org.springframework:spring-web:jar:4.3.19.RELEASE to keep the version consistency.

Dependency tree---------
[INFO] io.rest-assured:spring-mock-mvc:jar:3.3.0
[INFO] +- io.rest-assured:rest-assured:jar:3.3.0:compile
[INFO] | +- org.codehaus.groovy:groovy:jar:2.4.15:compile
[INFO] | +- org.codehaus.groovy:groovy-xml:jar:2.4.15:compile
[INFO] | | - (org.codehaus.groovy:groovy:jar:2.4.15:compile - omitted for duplicate)
[INFO] | +- org.apache.httpcomponents:httpclient:jar:4.5.3:compile
[INFO] | | +- org.apache.httpcomponents:httpcore:jar:4.4.6:compile
[INFO] | | +- commons-logging:commons-logging:jar:1.2:compile
[INFO] | | - commons-codec:commons-codec:jar:1.9:compile
[INFO] | +- org.apache.httpcomponents:httpmime:jar:4.5.1:compile
[INFO] | | - (org.apache.httpcomponents:httpclient:jar:4.5.1:compile - omitted for conflict with 4.5.3)
[INFO] | +- org.hamcrest:hamcrest-core:jar:1.3:compile
[INFO] | +- org.hamcrest:hamcrest-library:jar:1.3:compile
[INFO] | | - (org.hamcrest:hamcrest-core:jar:1.3:compile - omitted for duplicate)
[INFO] | +- org.ccil.cowan.tagsoup:tagsoup:jar:1.2.1:compile
[INFO] | +- io.rest-assured:json-path:jar:3.2.0:compile
[INFO] | | +- org.codehaus.groovy:groovy-json:jar:2.4.15:compile
[INFO] | | | - (org.codehaus.groovy:groovy:jar:2.4.15:compile - omitted for duplicate)
[INFO] | | +- (org.codehaus.groovy:groovy:jar:2.4.15:compile - omitted for duplicate)
[INFO] | | - io.rest-assured:rest-assured-common:jar:3.2.0:compile
[INFO] | | +- (org.codehaus.groovy:groovy:jar:2.4.15:compile - omitted for duplicate)
[INFO] | | - (org.apache.commons:commons-lang3:jar:3.4:compile - omitted for duplicate)
[INFO] | - io.rest-assured:xml-path:jar:3.2.0:compile
[INFO] | +- (org.codehaus.groovy:groovy-xml:jar:2.4.15:compile - omitted for duplicate)
[INFO] | +- (org.codehaus.groovy:groovy:jar:2.4.15:compile - omitted for duplicate)
[INFO] | +- (io.rest-assured:rest-assured-common:jar:3.2.0:compile - omitted for duplicate)
[INFO] | +- org.apache.commons:commons-lang3:jar:3.4:compile
[INFO] | +- (org.ccil.cowan.tagsoup:tagsoup:jar:1.2.1:compile - omitted for duplicate)
[INFO] | +- javax.xml.bind:jaxb-api:jar:2.2.12:compile
[INFO] | +- com.sun.xml.bind:jaxb-osgi:jar:2.2.10:compile
[INFO] | - org.apache.sling:org.apache.sling.javax.activation:jar:0.1.0:compile
[INFO] | - javax.activation:activation:jar:1.1.1:compile
[INFO] +- io.rest-assured:spring-commons:jar:3.2.0:compile
[INFO] | - (io.rest-assured:rest-assured:jar:3.2.0:compile - omitted for duplicate)
[INFO] +- org.springframework:spring-test:jar:4.2.6.RELEASE:compile
[INFO] | - org.springframework:spring-core:jar:4.2.6.RELEASE:compile
[INFO] | - (commons-logging:commons-logging:jar:1.2:compile - omitted for duplicate)
[INFO] +- org.springframework:spring-webmvc:jar:4.2.6.RELEASE:compile
[INFO] | +- org.springframework:spring-beans:jar:4.2.6.RELEASE:compile
[INFO] | | - (org.springframework:spring-core:jar:4.2.6.RELEASE:compile - omitted for duplicate)
[INFO] | +- org.springframework:spring-context:jar:4.2.6.RELEASE:compile
[INFO] | | +- (org.springframework:spring-aop:jar:4.2.6.RELEASE:compile - omitted for conflict with 4.3.19.RELEASE)
[INFO] | | +- (org.springframework:spring-beans:jar:4.2.6.RELEASE:compile - omitted for duplicate)
[INFO] | | +- (org.springframework:spring-core:jar:4.2.6.RELEASE:compile - omitted for duplicate)
[INFO] | | - (org.springframework:spring-expression:jar:4.2.6.RELEASE:compile - omitted for duplicate)
[INFO] | +- (org.springframework:spring-core:jar:4.2.6.RELEASE:compile - omitted for duplicate)
[INFO] | +- org.springframework:spring-expression:jar:4.2.6.RELEASE:compile
[INFO] | | - (org.springframework:spring-core:jar:4.2.6.RELEASE:compile - omitted for duplicate)
[INFO] | - org.springframework:spring-web:jar:4.2.6.RELEASE:compile
[INFO] | +- (org.springframework:spring-aop:jar:4.2.6.RELEASE:compile - omitted for duplicate)
[INFO] | +- (org.springframework:spring-beans:jar:4.2.6.RELEASE:compile - omitted for duplicate)
[INFO] | +- (org.springframework:spring-context:jar:4.2.6.RELEASE:compile - omitted for duplicate)
[INFO] | - (org.springframework:spring-core:jar:4.2.6.RELEASE:compile - omitted for duplicate)
[INFO] +- org.springframework.security:spring-security-core:jar:4.2.9.RELEASE:compile
[INFO] | +- aopalliance:aopalliance:jar:1.0:compile
[INFO] | +- org.springframework:spring-aop:jar:4.3.19.RELEASE:compile
[INFO] | | +- (org.springframework:spring-beans:jar:4.3.19.RELEASE:compile - omitted for conflict with 4.2.6.RELEASE)
[INFO] | | - (org.springframework:spring-core:jar:4.3.19.RELEASE:compile - omitted for conflict with 4.2.6.RELEASE)
[INFO] | +- (org.springframework:spring-beans:jar:4.3.19.RELEASE:compile - omitted for conflict with 4.2.6.RELEASE)
[INFO] | +- (org.springframework:spring-context:jar:4.3.19.RELEASE:compile - omitted for conflict with 4.2.6.RELEASE)
[INFO] | +- (org.springframework:spring-core:jar:4.3.19.RELEASE:compile - omitted for conflict with 4.2.6.RELEASE)
[INFO] | - (org.springframework:spring-expression:jar:4.3.19.RELEASE:compile - omitted for conflict with 4.2.6.RELEASE)
[INFO] +- org.springframework.security:spring-security-test:jar:4.2.9.RELEASE:compile
[INFO] | +- (org.springframework.security:spring-security-core:jar:4.2.9.RELEASE:compile - omitted for duplicate)
[INFO] | +- org.springframework.security:spring-security-web:jar:4.2.9.RELEASE:compile
[INFO] | | +- (aopalliance:aopalliance:jar:1.0:compile - omitted for duplicate)
[INFO] | | +- (org.springframework.security:spring-security-core:jar:4.2.9.RELEASE:compile - omitted for duplicate)
[INFO] | | +- (org.springframework:spring-beans:jar:4.3.19.RELEASE:compile - omitted for conflict with 4.2.6.RELEASE)
[INFO] | | +- (org.springframework:spring-context:jar:4.3.19.RELEASE:compile - omitted for conflict with 4.2.6.RELEASE)
[INFO] | | +- (org.springframework:spring-core:jar:4.3.19.RELEASE:compile - omitted for conflict with 4.2.6.RELEASE)
[INFO] | | +- (org.springframework:spring-expression:jar:4.3.19.RELEASE:compile - omitted for conflict with 4.2.6.RELEASE)
[INFO] | | - (org.springframework:spring-web:jar:4.3.19.RELEASE:compile - omitted for conflict with 4.2.6.RELEASE)
[INFO] | +- (org.springframework:spring-core:jar:4.3.19.RELEASE:compile - omitted for conflict with 4.2.6.RELEASE)
[INFO] | - (org.springframework:spring-test:jar:4.3.19.RELEASE:compile - omitted for conflict with 4.2.6.RELEASE)
[INFO] +- org.apache.geronimo.specs:geronimo-servlet_3.0_spec:jar:1.0:provided
[INFO] +- junit:junit:jar:4.12:test
[INFO] | - (org.hamcrest:hamcrest-core:jar:1.3:test - omitted for duplicate)
[INFO] +- commons-io:commons-io:jar:2.4:test
[INFO] +- org.assertj:assertj-core:jar:1.7.0:test
[INFO] +- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.11:test
[INFO] | - (org.codehaus.jackson:jackson-core-asl:jar:1.9.11:test - omitted for duplicate)
[INFO] +- org.codehaus.jackson:jackson-core-asl:jar:1.9.11:test
[INFO] +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.7:test
[INFO] | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:test
[INFO] | - com.fasterxml.jackson.core:jackson-core:jar:2.9.7:test
[INFO] +- org.powermock:powermock-reflect:jar:1.5.6:test
[INFO] | - org.objenesis:objenesis:jar:2.1:test
[INFO] - org.springframework.restdocs:spring-restdocs-mockmvc:jar:1.0.0.RELEASE:test
[INFO] +- (org.springframework:spring-test:jar:4.1.7.RELEASE:test - omitted for conflict with 4.2.6.RELEASE)
[INFO] - org.springframework.restdocs:spring-restdocs-core:jar:1.0.0.RELEASE:test
[INFO] +- (junit:junit:jar:4.12:test - omitted for duplicate)
[INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:test
[INFO] +- (org.springframework:spring-webmvc:jar:4.1.7.RELEASE:test - omitted for conflict with 4.2.6.RELEASE)
[INFO] - (com.fasterxml.jackson.core:jackson-databind:jar:2.9.7:test - version managed from 2.4.6.1; omitted for duplicate)

@HelloCoCooo HelloCoCooo changed the title Multiple versions of Multiple versions of org.springframework:spring-web:jar, leading to inconsistent semantic behaviors Mar 3, 2019
@HelloCoCooo
Copy link
Contributor Author

HelloCoCooo commented Mar 3, 2019

The code snippets of the above risky methods defined in class SpringHandlerInstantiator in verison org.springframework:spring-web:jar:4.3.19.RELEASE ----
multiple4 3 19

Class SpringHandlerInstantiator included in org.springframework:spring-web:jar:4.2.6.RELEASE does not contain the risky methods.

The code snippets of the methods with same signatures as the above risky methods defined in the superclass HandlerInstantiator in org.springframework:spring-web:jar:4.2.6.RELEASE----
1y4 2 6
2y4 2 6
3y4 2 6
4y4 2 6
5y4 2 6
6y4 2 6

Obviously, the risky methods in newer version org.springframework:spring-web:jar:4.3.19.RELEASE deal with more cases and adds more control branches, which change the control flows and data flows. So referencing the methods defined in superclass HandlerInstantiator belonging to org.springframework:spring-web:jar:4.2.6.RELEASE by dynamic binding, may lead to inconsisitent semantic behaviors.

Thanks again.

@HelloCoCooo
Copy link
Contributor Author

HelloCoCooo commented Mar 3, 2019

Using the following test case to run on these two versions of methods separately starting from the entry method springHandlerInstantiator.namingStrategyInstance(deserializationConfig, null, implClass) in your project, then we can find that variable propertyNamingStrategy is assigned different values.
rest-assured_test.txt

Please check whether the changes of this variable value will affect your semantic behaviors.

I can submit a PR to fix it, if you concern this issue.

@johanhaleby
Copy link
Collaborator

@HelloCoCooo Yes please, that would be great

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants