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

Avoid dependency on WebUtils for extracting file extension [SPR-14479] #19048

Closed
spring-projects-issues opened this issue Jul 18, 2016 · 2 comments
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Jul 18, 2016

Brian Clozel opened SPR-14479 and commented

When running a web reactive project without the servlet dependency, we're getting a NCDFE because PathExtensionContentTypeResolver.extractKey is calling WebUtils.extractFullFilenameFromUrlPath which itself is importing/using the Servlet API extensively.

java.lang.NoClassDefFoundError: javax/servlet/ServletRequest
	at org.springframework.web.reactive.accept.PathExtensionContentTypeResolver.extractKey(PathExtensionContentTypeResolver.java:89) ~[spring-web-reactive-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
	at org.springframework.web.reactive.accept.AbstractMappingContentTypeResolver.resolveMediaTypes(AbstractMappingContentTypeResolver.java:91) ~[spring-web-reactive-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
	at org.springframework.web.reactive.accept.CompositeContentTypeResolver.resolveMediaTypes(CompositeContentTypeResolver.java:77) ~[spring-web-reactive-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
	at org.springframework.web.reactive.result.ContentNegotiatingResultHandlerSupport.getAcceptableTypes(ContentNegotiatingResultHandlerSupport.java:130) ~[spring-web-reactive-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
	at org.springframework.web.reactive.result.ContentNegotiatingResultHandlerSupport.selectMediaType(ContentNegotiatingResultHandlerSupport.java:102) ~[spring-web-reactive-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
	at org.springframework.web.reactive.result.method.annotation.AbstractMessageConverterResultHandler.writeBody(AbstractMessageConverterResultHandler.java:118) ~[spring-web-reactive-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
	at org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler.handleResult(ResponseBodyResultHandler.java:119) ~[spring-web-reactive-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
	at org.springframework.web.reactive.DispatcherHandler.handleResult(DispatcherHandler.java:126) ~[spring-web-reactive-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
	at org.springframework.web.reactive.DispatcherHandler.lambda$handle$2(DispatcherHandler.java:113) ~[spring-web-reactive-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
	at reactor.core.publisher.MonoThenApply$MonoThenApplyManager.onNext(MonoThenApply.java:99) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.Operators$DeferredScalarSubscriber.complete(Operators.java:796) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.MonoThenApply$MonoThenApplyManager$SecondSubscriber.onNext(MonoThenApply.java:204) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.FluxResume$ResumeSubscriber.onNext(FluxResume.java:75) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:131) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:1292) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:187) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:1009) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.FluxResume$ResumeSubscriber.onSubscribe(FluxResume.java:70) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:100) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:172) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.MonoThenApply.subscribe(MonoThenApply.java:51) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.MonoMapFuseable.subscribe(MonoMapFuseable.java:69) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.MonoOtherwise.subscribe(MonoOtherwise.java:47) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.MonoThenApply$MonoThenApplyManager.onNext(MonoThenApply.java:133) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:71) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:391) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onSubscribe(FluxConcatMap.java:192) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:95) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:59) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.FluxConcatMap.subscribe(FluxConcatMap.java:116) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.MonoNext.subscribe(MonoNext.java:45) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.MonoOtherwiseIfEmpty.subscribe(MonoOtherwiseIfEmpty.java:47) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.MonoThenApply.subscribe(MonoThenApply.java:58) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.MonoThenApply.subscribe(MonoThenApply.java:58) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.MonoOtherwise.subscribe(MonoOtherwise.java:47) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.MonoOtherwise.subscribe(MonoOtherwise.java:47) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.MonoOtherwise.subscribe(MonoOtherwise.java:47) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.MonoThenSupply$MonoConcatIgnoreManager.drain(MonoThenSupply.java:169) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.core.publisher.MonoThenSupply.subscribe(MonoThenSupply.java:55) ~[reactor-core-3.0.0.BUILD-20160718.121732-24.jar:na]
	at reactor.io.netty.http.NettyHttpServerHandler.channelRead(NettyHttpServerHandler.java:91) ~[reactor-netty-0.5.0.BUILD-20160718.122522-17.jar:na]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:372) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:358) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:350) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:435) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:250) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:372) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:358) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:350) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:372) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:358) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:123) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:571) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:512) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:426) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:398) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:877) [netty-all-4.1.3.Final.jar:4.1.3.Final]
	at java.lang.Thread.run(Thread.java:745) [na:1.8.0_92]
Caused by: java.lang.ClassNotFoundException: javax.servlet.ServletRequest
	at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_92]
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_92]
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) ~[na:1.8.0_92]
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_92]
	... 62 common frames omitted


Affects: 4.3.1, 5.0 M1

Issue Links:

Referenced from: commits b583aa1, adc595b

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

Let's extract those methods out to a more general utility class. I'll do that for 5.0 M1 still.

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

Since our extract*Filename* methods in WebUtils were only really used with a subsequent StringUtils.getFilenameExtension call, it seems worth factoring out a dedicated extractFileExtension method into UriUtils (using URI terminology there) which also allows for more efficient String parsing.

In order to deprecate the WebUtils variants in 4.3.2 already, I'm backporting that extraction to 4.3.x, removing the old method variants in 5.0 to begin with.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants