Nik Silver
Nik Silver

Reputation: 364

NoClassDefFoundError for Play app with sbt using Eclipse

I am trying to write a Play 2.3.8 application in Scala, managing it via sbt but editing it in Eclipse. I worked round one problem, but this seems to introduce another, and cannot work out how to solve it.

I set up the project using the exact instructions to Create a new application without Activator (except I also add

scalaVersion := "2.11.6"

to build.sbt), then I cd to my project directory, type sbt and once in sbt I type eclipse. Then I open Eclipse and happily import the project.

Now I create a simple template (app/views/Application/index.scala.html) and a controller which calls it (app/controllers/Application.scala). When I go into sbt and type run I can happily open my web browser at localhost:9000 and my populated template appears.

All is good apart from one problem (the first one). When I open up Application.scala in Eclipse I get a wiggly red error line saying "object Application is not a member of package views.html". I solved that using Nick Cooper's answer elsewhere on Stack Overflow. He said to go to Project > Properties > Java Build Path > Libraries > Add Class Folder... and then add target/scala-2.11/classes_managed. That makes the error go away. But I don't want to manage Eclipse's settings directly; I want to manage everything via sbt. So by trial and error I found that I can add this line to my build.sbt file...

unmanagedJars in Compile += ( baseDirectory.value / "target/scala-2.11/classes_managed" )

...and now I can type sbt followed by eclipse and Eclipse's config is generated correctly, with no wiggly red line errors.

But this creates a second problem. It turns out that by introducing that line into build.sbt the application no longer runs. Specifically when I go into sbt, type run and open localhost:9000 I get a NoClassDefFoundError exception in my sbt console:

java.lang.NoClassDefFoundError: controllers/Application$
    at Routes$$anonfun$routes$1$$anonfun$applyOrElse$1$$anonfun$apply$1.apply(routes_routing.scala:51) ~[classes_managed/:na]
    at Routes$$anonfun$routes$1$$anonfun$applyOrElse$1$$anonfun$apply$1.apply(routes_routing.scala:51) ~[classes_managed/:na]
    at play.core.Router$HandlerInvokerFactory$$anon$13$$anon$14.call(Router.scala:217) ~[play_2.11-2.3.8.jar:2.3.8]
    at play.core.Router$Routes$TaggingInvoker.call(Router.scala:464) ~[play_2.11-2.3.8.jar:2.3.8]
    at Routes$$anonfun$routes$1$$anonfun$applyOrElse$1.apply(routes_routing.scala:51) ~[classes_managed/:na]
Caused by: java.lang.ClassNotFoundException: controllers.Application$
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_40]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_40]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_40]
    at Routes$$anonfun$routes$1$$anonfun$applyOrElse$1$$anonfun$apply$1.apply(routes_routing.scala:51) ~[classes_managed/:na]
    at Routes$$anonfun$routes$1$$anonfun$applyOrElse$1$$anonfun$apply$1.apply(routes_routing.scala:51) ~[classes_managed/:na]
[error] application - Error while rendering default error page
scala.MatchError: java.lang.NoClassDefFoundError: controllers/Application$ (of class java.lang.NoClassDefFoundError)
    at play.api.GlobalSettings$class.onError(GlobalSettings.scala:148) ~[play_2.11-2.3.8.jar:2.3.8]
    at play.api.DefaultGlobal$.onError(GlobalSettings.scala:206) [play_2.11-2.3.8.jar:2.3.8]
    at play.core.server.Server$class.logExceptionAndGetResult$1(Server.scala:63) [play_2.11-2.3.8.jar:2.3.8]
    at play.core.server.Server$$anonfun$getHandlerFor$4.apply(Server.scala:73) [play_2.11-2.3.8.jar:2.3.8]
    at play.core.server.Server$$anonfun$getHandlerFor$4.apply(Server.scala:71) [play_2.11-2.3.8.jar:2.3.8]

You can see the entire (tiny) codebase on Github.

All the class files seem to be all there, and in exactly the same locations, regardless of whether or not I include the "unmanagedJars" line. It's not an Eclipse problem because it happens even when Eclipse is closed. It seems to be a classpath issue (but I can't understand why adding to a classpath should hide some classes). Regardless of that, I'd like to manage my project with sbt and use Eclipse just as the editor. What am I getting wrong?

Upvotes: 1

Views: 1233

Answers (2)

Johnny
Johnny

Reputation: 1393

I am using activator but I guess it might be the same.

So, Eclipse does not really like structural changes in a Play project or adding/removing libraries (via libraryDependencies, etc) and displays red squiggly things everywhere. This is how I solve them:

activator clean compile

If I have added/removed libraries, I run

activator eclipse

so that Eclipse gets the changes.

It works everytime. Clean, clean, clean. I actually found this solution somewhere on the Net a while a go but cannot remember where, sorry.

EDIT

And refresh the project in Eclipse!

Upvotes: 0

Nik Silver
Nik Silver

Reputation: 364

I have found a solution through further trial and error. Instead of extending the classpath to "target/scala-2.11/classes_managed" it should be extended to "target/scala-2.11/classes". In other words the line in build.sbt should be

unmanagedJars in Compile += ( baseDirectory.value / "target/scala-2.11/classes" )

Now from sbt I can compile, test and run the application, and connect successfully to localhost:9000, and I can also open the files in Eclipse without seeing error lines.

I still don't know why the NoClassDefFoundError really occurred in the previous setup, but that's a problem for another day.

Upvotes: 1

Related Questions