Running skinny-blank-app for the first time generates NPE
akirarat opened this issue · comments
I downloaded skinny-blank-app.zip from the hompage, unzipped and ran "skinny run" and generates a NPE when I go to localhost:8080
$ ./skinny run
[info] Loading settings for project global-plugins from idea.sbt ...
[info] Loading global plugins from /Users/xxx/.sbt/1.0/plugins
[info] Loading settings for project skinny-blank-app-build from plugins.sbt ...
[info] Loading project definition from /Users/xxx/git/skinny-blank-app/project
[info] Loading settings for project dev from build.sbt ...
[info] Set current project to skinny-blank-app-dev (in build file:/Users/xxx/git/skinny-blank-app/)
2019-09-12 15:19:28.792:INFO::pool-53-thread-1: Logging initialized @11572ms to org.eclipse.jetty.util.log.StdErrLog
2019-09-12 15:19:28.889:INFO:oejs.Server:pool-53-thread-1: jetty-9.4.16.v20190411; built: 2019-04-11T15:03:03.392Z; git: e0aa4ae4c0fe2e6bb3ecde2eb3e54bc3087b2f52; jvm 1.8.0_201-b09
2019-09-12 15:19:29.016:INFO:oejw.StandardDescriptorProcessor:pool-53-thread-1: NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet
2019-09-12 15:19:29.048:INFO:oejs.session:pool-53-thread-1: DefaultSessionIdManager workerName=node0
2019-09-12 15:19:29.048:INFO:oejs.session:pool-53-thread-1: No SessionScavenger set, using defaults
2019-09-12 15:19:29.049:INFO:oejs.session:pool-53-thread-1: node0 Scavenging every 600000ms
2019-09-12 15:19:29.176 INFO --- [ool-53-thread-1] skinny.micro.SkinnyListener : The cycle class name from the config: Bootstrap
2019-09-12 15:19:29.384 DEBUG --- [ool-53-thread-1] skinny.micro.SkinnyListener : Loaded lifecycle class: class Bootstrap
2019-09-12 15:19:29.457 INFO --- [ool-53-thread-1] skinny.micro.SkinnyListener : Initializing life cycle class: Bootstrap
2019-09-12 15:19:29.713 DEBUG --- [ool-53-thread-1] scalikejdbc.ConnectionPool$ : Registered connection pool : ConnectionPool(url:jdbc:h2:file:./db/development;MODE=PostgreSQL;AUTO_SERVER=TRUE, user:sa) using factory : <default>
2019-09-12 15:19:30.313:INFO:oejsh.ContextHandler:pool-53-thread-1: Started o.e.j.w.WebAppContext@75f13c3b{/,[file:///Users/xxx/git/skinny-blank-app/src/main/webapp/],AVAILABLE}
2019-09-12 15:19:30.496:INFO:oejs.AbstractConnector:pool-53-thread-1: Started ServerConnector@39be3791{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2019-09-12 15:19:30.497:INFO:oejs.Server:pool-53-thread-1: Started @13277ms
[success] Total time: 2 s, completed Sep 12, 2019 3:19:30 PM
1. Waiting for source changes in project dev... (press enter to interrupt)
2019-09-12 15:19:32.418 ERROR --- [p1804134626-390] controller.Controllers$root$ : <null>
java.lang.NullPointerException: null
at java.io.File.<init>(File.java:277)
at skinny.controller.feature.ScalateTemplateEngineFeature.generateWelcomePageIfAbsent(ScalateTemplateEngineFeature.scala:150)
at skinny.controller.feature.ScalateTemplateEngineFeature.generateWelcomePageIfAbsent$(ScalateTemplateEngineFeature.scala:145)
at skinny.controller.SkinnyController.generateWelcomePageIfAbsent(SkinnyController.scala:8)
at skinny.controller.feature.ScalateTemplateEngineFeature.templateExists(ScalateTemplateEngineFeature.scala:126)
at skinny.controller.feature.ScalateTemplateEngineFeature.templateExists$(ScalateTemplateEngineFeature.scala:123)
at skinny.controller.SkinnyController.templateExists(SkinnyController.scala:8)
at skinny.controller.feature.TemplateEngineFeature.render(TemplateEngineFeature.scala:29)
at skinny.controller.feature.TemplateEngineFeature.render$(TemplateEngineFeature.scala:26)
at skinny.controller.SkinnyController.render(SkinnyController.scala:8)
at controller.RootController.index(RootController.scala:7)
at controller.Controllers$root$.$anonfun$indexUrl$1(Controllers.scala:14)
at skinny.micro.SkinnyMicroBase.liftAction(SkinnyMicroBase.scala:300)
at skinny.micro.SkinnyMicroBase.liftAction$(SkinnyMicroBase.scala:298)
at skinny.controller.SkinnyController.liftAction(SkinnyController.scala:8)
at skinny.micro.SkinnyMicroBase.$anonfun$invoke$1(SkinnyMicroBase.scala:294)
at skinny.micro.ApiFormats.withRouteMultiParams(ApiFormats.scala:196)
at skinny.micro.ApiFormats.withRouteMultiParams$(ApiFormats.scala:182)
at skinny.controller.SkinnyController.withRouteMultiParams(SkinnyController.scala:8)
at skinny.micro.SkinnyMicroBase.invoke(SkinnyMicroBase.scala:294)
at skinny.micro.SkinnyMicroBase.invoke$(SkinnyMicroBase.scala:292)
at skinny.controller.SkinnyController.invoke(SkinnyController.scala:8)
at skinny.micro.SkinnyMicroBase.$anonfun$executeRoutes$15(SkinnyMicroBase.scala:208)
at scala.collection.immutable.Stream.flatMap(Stream.scala:489)
at skinny.micro.SkinnyMicroBase.runActions$1(SkinnyMicroBase.scala:208)
at skinny.micro.SkinnyMicroBase.$anonfun$executeRoutes$16(SkinnyMicroBase.scala:241)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
at skinny.micro.SkinnyMicroBase.cradleHalt$1(SkinnyMicroBase.scala:215)
at skinny.micro.SkinnyMicroBase.executeRoutes(SkinnyMicroBase.scala:239)
at skinny.micro.SkinnyMicroBase.executeRoutes$(SkinnyMicroBase.scala:135)
at skinny.controller.SkinnyController.executeRoutes(SkinnyController.scala:8)
at skinny.micro.SkinnyMicroBase.$anonfun$handle$1(SkinnyMicroBase.scala:110)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
at scala.util.DynamicVariable.withValue(DynamicVariable.scala:62)
at skinny.micro.base.SkinnyContextInitializer.withResponse(SkinnyContextInitializer.scala:98)
at skinny.micro.base.SkinnyContextInitializer.withResponse$(SkinnyContextInitializer.scala:96)
at skinny.controller.SkinnyController.withResponse(SkinnyController.scala:8)
at skinny.micro.base.SkinnyContextInitializer.$anonfun$withRequestResponse$1(SkinnyContextInitializer.scala:78)
at scala.util.DynamicVariable.withValue(DynamicVariable.scala:62)
at skinny.micro.base.SkinnyContextInitializer.withRequest(SkinnyContextInitializer.scala:89)
at skinny.micro.base.SkinnyContextInitializer.withRequest$(SkinnyContextInitializer.scala:87)
at skinny.controller.SkinnyController.withRequest(SkinnyController.scala:8)
at skinny.micro.base.SkinnyContextInitializer.withRequestResponse(SkinnyContextInitializer.scala:77)
at skinny.micro.base.SkinnyContextInitializer.withRequestResponse$(SkinnyContextInitializer.scala:75)
at skinny.controller.SkinnyController.withRequestResponse(SkinnyController.scala:8)
at skinny.micro.SkinnyMicroBase.handle(SkinnyMicroBase.scala:110)
at skinny.micro.SkinnyMicroBase.handle$(SkinnyMicroBase.scala:105)
at skinny.controller.SkinnyController.skinny$micro$contrib$FlashMapSupport$$super$handle(SkinnyController.scala:8)
at skinny.micro.contrib.FlashMapSupport.$anonfun$handle$1(FlashMapSupport.scala:66)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
at scala.util.DynamicVariable.withValue(DynamicVariable.scala:62)
at skinny.micro.base.SkinnyContextInitializer.withRequest(SkinnyContextInitializer.scala:89)
at skinny.micro.base.SkinnyContextInitializer.withRequest$(SkinnyContextInitializer.scala:87)
at skinny.controller.SkinnyController.withRequest(SkinnyController.scala:8)
at skinny.micro.contrib.FlashMapSupport.handle(FlashMapSupport.scala:39)
at skinny.micro.contrib.FlashMapSupport.handle$(FlashMapSupport.scala:38)
at skinny.controller.SkinnyController.skinny$micro$contrib$ScalateSupport$$super$handle(SkinnyController.scala:8)
at skinny.micro.contrib.ScalateSupport.handle(ScalateSupport.scala:132)
at skinny.micro.contrib.ScalateSupport.handle$(ScalateSupport.scala:131)
at skinny.controller.SkinnyController.handle(SkinnyController.scala:8)
at skinny.micro.SkinnyMicroFilterBase.$anonfun$doFilter$1(SkinnyMicroFilterBase.scala:29)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
at scala.util.DynamicVariable.withValue(DynamicVariable.scala:62)
at skinny.micro.SkinnyMicroFilterBase.doFilter(SkinnyMicroFilterBase.scala:29)
at skinny.micro.SkinnyMicroFilterBase.doFilter$(SkinnyMicroFilterBase.scala:20)
at skinny.controller.SkinnyController.doFilter(SkinnyController.scala:8)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:540)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1700)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1345)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:480)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1667)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1247)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:220)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.Server.handle(Server.java:505)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:370)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:267)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:786)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:743)
at java.lang.Thread.run(Thread.java:748)
Using Java 1.8.0_201-b09
I also tried the instructions from the homepage.
/skinny g scaffold members member name:String activated:Boolean luckyNumber:Option[Long] birthday:Option[LocalDate]
./skinny db:migrate
./skinny run
Then hit http://localhost:8080/members
Same NPE stacktrace.
java.lang.NullPointerException: null
at java.io.File.(File.java:277)
at skinny.controller.feature.ScalateTemplateEngineFeature.generateWelcomePageIfAbsent(ScalateTemplateEngineFeature.scala:150)
.. and so forth.
hmm, I'm still not sure about how to reproduce your problem yet.
This is a MacOS Catalina (10.15) specific bug.
All user files and directories are mounted under /System/Volumes/Data and MacOS mounted in a read-only partition, not accessible to users.
The index.html.ssp file now has an alias (symbolic link). For example, the resource path:
/WEB-INF/views/root/index.html.ssp
Will resolve to this file path:
file:///Users/xxx/git/siptea/src/main/webapp/WEB-INF/views/root/index.html.ssp
And also have an alias path:
/System/Volumes/Data/Users/xxx/git/siptea/src/main/webapp/WEB-INF/views/root/index.html.ssp
Inside org.eclipse.jetty.server.handler.ContextHandler#checkAlias, it will return true for resource.isAlias() but later fail in org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker#check because hasSymbolicLink(path) will return false, when it should return true.
A simple unit test finds the problem. Files.isSymbolicLink(path1) should return true but it isn't, causing the caller, hasSymbolicLink(), to return false. I'm not sure how to fix the problem yet. I'll try upgrading to the newest Catalina and try again.
class FilesSameTest extends FlatSpec {
"2 files" should "be the same" in {
val path1 = Paths.get("/Users/xxx/git/siptea/src/main/webapp/WEB-INF/views/root/index.html.ssp")
val path2 = Paths.get("/System/Volumes/Data/Users/xxx/git/siptea/src/main/webapp/WEB-INF/views/root/index.html.ssp")
println(hasSymbolicLink(path1)) // returns false
println(Files.isSameFile(path1, path2)) // returns true
println(Files.isSymbolicLink(path1)) // returns false
}
// Copy pasted from AllowSymLinkAliasChecker#hasSymbolicLink
private def hasSymbolicLink(path: Path): Boolean = { // Is file itself a symlink?
if (Files.isSymbolicLink(path)) return true
// Lets try each path segment
var base = path.getRoot
import scala.collection.JavaConversions._
for (segment <- path) {
base = base.resolve(segment)
if (Files.isSymbolicLink(base)) return true
}
false
}
I upgraded to the newest Catalina and path1.toRealPath() returns the "/User/home..." string instead of "/System/Volumes/Data..." string. Seems like this is fixed.