Summary
I am having difficulty running and debugging a CLI application built with SBT Native Packager - browsing similar questions yielded little insight as they are either referring directly to JDK packager (via JavaFX) or are simply incomplete/unanswered. Running the application throws an error message that is hard to reason about and/or track down the root cause of (no logs).
Stack
JDK 8u60
SBT 0.13.9
sbt-native-packager 1.0.6
Inno Setup 5.5.8
The intention is to build Windows installation package - which seems correctly built (I am able to install it to another machine).
Error details
After installing the packaged app, one of two happens:
running the app without any command parameters does nothing (no errors printed to console, dead silent)
running the app with a parameter --help (which hits a code path in main method that prints out the help file) yields "Error invoking method" followed with "Failed to launch JVM" errors. I could not find any error logs or further precise hints. The application's bootstrap is practically a single class (containing main()) contained in its own SBT module, which in turn produces its own JAR.
Investigation
In absence of any idea where to start I started to investigate this with following results:
there are two bootstrap JARs produced, let's call them bootstrap.jar and bootstrap-launcher.jar
both contain MANIFEST.MF with the Main-Class element correctly populated
the former doesn't contain Class-Path element but contains elements like Implementation-Title and so on. It contains the compiled bootstrap class at the expected package. The Main-Class in its manifest file points to that package.
the latter is directly opposite the former: its manifest file contains Class-Path and Main-Class elements, nothing else. Additionally, it doesn't contain any compiled code whatsoever
Experiments
I performed the following experiments with bootstrap JARs:
deleting bootstrap.jar or bootstrap-launcher.jar
renaming and overwriting bootstrap-launcher.jar -> bootstrap.jar
renaming and overwriting bootstrap.jar -> bootstrap-launcher.jar
manually adding Class-Path entries from bootstrap.jar manifest file to bootstrap-launcher.jar's manifest file (a.k.a. desperation mode)
end result of these experiments is always the same: 'Class com...Bootstrap not found' exception thrown in a GUI window; no further explanations or stacktraces
At this point in time I have no other ideas so I would appreciate any insight.
Additionally, I see library dependencies correctly materialized in lib directory, so at least I surmise this is working correctly.
build.sbt
Lastly, for completion, I am attaching my current build.sbt file. The reason it's structured as is, is because I used to use sbt-assembly to produce a fat JAR - it worked quite nicely but new packaging was requested. Tracing down the issue, I removed all traces of sbt-assembly from build, except from plugins.sbt (simply as convenience of easier fallback, should the need arise).
lazy val root: Project = (project in file("."))
.aggregate(common, commonTest, core, bootstrapCli)
lazy val common: Project = (project in file("common"))
.settings(
libraryDependencies := ...
lazy val commonTest: Project = (project in file("commonTest"))
.dependsOn(common % "compile -> test")
.settings(
libraryDependencies := ...
)
lazy val core: Project = (project in file ("core"))
.dependsOn(common, commonTest % "test -> test")
.settings(
libraryDependencies := ...,
javacOptions in (Compile, compile) ++= Seq("-parameters"),
javacOptions in doc ++= Seq.empty,
)
lazy val bootstrapCli: Project = (project in file("bootstrapCli"))
.dependsOn(core % "compile -> compile;test -> test")
.enablePlugins(JDKPackagerPlugin)
.settings(
jdkPackagerType := "exe",
mainClass in Compile := Some("com._3esi.load.bootstrap.cli.Bootstrap")
)
Again, I'd greatly appreciate any insight.
Related
I have a gradle project (converted from an original ANT project). The directory structure is as advised by gradle so my source is in src\main\java and test is in src\test\java.
However, because the package structure of src\test is almost exactly similar to src\main, during the test run phase in gradle, I get a bunch of
java.lang.NoClassDefFoundError
even though I can clearly see the code under ,say, src\main\A.B.C\Y\X.java. I am suspecting that while running the tests, the class to import is being searched under src\test\A.B.C\Y where, of course, the class X is not present
We have a Play project with folder structure given in the link https://www.playframework.com/documentation/2.5.x/Anatomy.
We have addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.2") in plugins.sbt and in build.sbt we have added the below lines,
lazy val root = (project in file(".")).enablePlugins(PlayJava)
scalaVersion := "2.11.7"
While we give compile command (through activator), the project loads the dependency jars from build.sbt, but the .classes files are not generated in target folder.
Could anyone please help us in solving the issue?
We have solved the issue by adding the following line to build.sbt file,
javaSource in Compile := baseDirectory.value / "app"
After the addition of this, the .java files and .scala files inside the "app" folder gets compiled.
I have a Spring Boot Gradle project setup in Spring Tools Suite (3.7.2 RELEASE) with the following source folders:
- src/integration-test/java
- src/integration-test/resources
- src/main/java
- src/main/resources
- src/test/java
- src/test/resources`
Whenever I run the application or unit tests from within STS, I see that STS is using the resources found under src/integration-test/resources.
I see a duplicate resource warning in STS for files which exist in all 3 resource source folders. For example, I have an application.properties in all 3 source folders and I see following:
The resource is a duplicate of src/integration-test/resources/application.properties and was not copied to the output folder
If I run the application as a JAR or unit tests/integration tests from the command line (via gradle build), everything seems to use the correct resources. This makes me believe it is a problem with how STS/Eclipse is handling gradle.
Does anybody know of how I can configure STS to use the correct resource source folders when using gradle?
I think my problem may be related to (or the same as?) Spring Boot incorrectly loads test configuration when running from eclipse+gradle, https://issuetracker.springsource.com/browse/STS-3882, https://issues.gradle.org/browse/GRADLE-1777
I also tried the solution found here, but that seems to only fix Maven builds:
Spring Tool Suite finds spring-boot integration test configuration and does not start main application
I think my problem may be related to...
Yes, it is related but in my opinion not the same. That problem is caused by the runtime classpath being incorrect. This problem is an error coming from the eclipse project builder so it is a compile-time issue.
The problems are closely related though. Depending on your point of view, you could say they are the same (incorrect mixing of test and compile-time classpaths).
Here, specifically, the problem is that the eclipse builder tries to copy all the resources it finds in source folders to the project's single output folder. Each source folder has a 'application.properties'. The builder warns that it could not copy some of them because one would overwrite the other.
I think there may be a solution for this problem. But it is a solution that really should come from Gradle + ( BuildShip | STS Gradle Tooling) than from you.
It is possible in Eclipse to configure each source-folder individually to target a specific outputfolder. Maven + M2E are doing this correcty, but Gradle + (BuildsShip | STS Gradle Tooling) combdos do not.
For example this is what maven puts into the eclipse .classpath file when it configures a test resources folder:
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
Notice how it explicitly sets the output folder for that entry (to something different from the project's default output folder).
You may be able to address the problem yourself by modifying the .classpath for a gradle project in a similar way. Either by doing it manually or from your build.gradle.
I'm not sure this is worth it however as you will then likely still get hit by the runtime classpath issue (since these folders will still be added to your runtime classpath, your runtime classpath will end-up with two appication.properties resources, one which will 'shadow' the other. See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=482315)
I would say, the right thing to do is add a comment to the issue I linked, and hope they fix it soon as there is only so much you can do yourself by hacking the build.gradle file to modify the .classpath (this can not solve the runtime classpath issue, but in order to solve the runtime classpath issue, they would have to configure source folders to target individual output folder similar to what m2e does).
I would add this as a comment to #Kris's answer but it's too long.
I have solved the runtime classpath issue by adding the code below to my build.gradle file. The code generates an Eclipse launch configuration for the Spring Boot application class and includes only the runtime classpath (i.e. no test JARs).
My project uses the Gradle 'eclipse' plugin to generate the Eclipse project files (which I then import into Eclipse). Running the eclipseClasspath Gradle target will generate the launch file in the project's root directory.
def mainClassName = "com.example.MyApplication"
task eclipseApplicationLaunch {
group "IDE"
description "Generate an Eclipse launch configuration file for the Spring Boot application class"
}
eclipseApplicationLaunch << {
def writer = new FileWriter("${mainClassName.substring(mainClassName.lastIndexOf(".")+1)}.launch")
def xml = new groovy.xml.MarkupBuilder(writer)
xml.doubleQuotes = true
xml.launchConfiguration(type: "org.eclipse.jdt.launching.localJavaApplication") {
listAttribute(key:"org.eclipse.debug.core.MAPPED_RESOURCE_PATHS") {
listEntry(value:"/${project.name}/src/main/java/${mainClassName.replace(".","/")}.java")
}
listAttribute(key:"org.eclipse.debug.core.MAPPED_RESOURCE_TYPES") {
listEntry(value:"1")
}
listAttribute(key:"org.eclipse.jdt.launching.CLASSPATH") {
listEntry(value:"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n<runtimeClasspathEntry containerPath=\"org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/\" javaProject=\"${project.name}\" path=\"1\" type=\"4\"/>\r\n")
listEntry(value:"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n<runtimeClasspathEntry path=\"3\" projectName=\"${project.name}\" type=\"1\"/>\r\n")
configurations.runtime.resolvedConfiguration.resolvedArtifacts.each { artifact ->
def filePath = artifact.file.canonicalPath.replace("\\","/")
listEntry(value:"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n<runtimeClasspathEntry externalArchive=\"${filePath}\" path=\"3\" type=\"2\"/>\r\n")
}
}
booleanAttribute(key:"org.eclipse.jdt.launching.DEFAULT_CLASSPATH", value:"false")
stringAttribute(key:"org.eclipse.jdt.launching.MAIN_TYPE", value:"${mainClassName}")
stringAttribute(key:"org.eclipse.jdt.launching.PROGRAM_ARGUMENTS", value:"--spring.profiles.active=local --spring.config.location=conf/")
stringAttribute(key:"org.eclipse.jdt.launching.PROJECT_ATTR", value:"${project.name}")
stringAttribute(key:"org.eclipse.jdt.launching.VM_ARGUMENTS", value:"-Djava.net.preferIPv4Stack=true")
}
writer.close()
}
eclipseClasspath.dependsOn eclipseApplicationLaunch
I haven't modified the Eclipse .classpath file as per Kris' suggestion. Instead, I have added #Profile("test") to my test application class and #ActiveProfiles("test") to my test classes.
IntelliJ: 14.1.4
Spark: 1.5 release source code
I'm importing Spark source code into IntelliJ, and following steps on Spark website.
I'm getting errors below when building and compiling the project. I've googled around and tried what is suggested here in spark user list to "Generate Sources and Update Folders" in Maven tool bar for "Spark Project External Flume Sink", but still with same errors.
I'm pretty sure it's a resolve issue since all other classes are successfully resolved. Maybe I'm not using IntelliJ correctly? Any suggestions please?
Error:(45, 66) not found: type SparkFlumeProtocol
val transactionTimeout: Int, val backOffInterval: Int) extends SparkFlumeProtocol with Logging {
^
Error:(70, 39) not found: type EventBatch
override def getEventBatch(n: Int): EventBatch = {
I've solved the problem, and it turns out that the "Spark Project External Flume Sink" is excluded when importing Spark source code under default settings.
What I did:
File -> Project Structure -> Modules -> "spark-streaming-flume-sink_2.10" -> Sources
in the tree display of folders, initially "target" folder is excluded, but the "SparkFlumeProtocol" and "EventBatch" classes are compiled into this folder.
set "target" folder as "Sources", then leave all under "target" as "Excluded" except for "scala-2.10", see attached screenshot.
In this way, the compiles classes are included and the classes can be resolved correctly after a re-build project.
--- update June-8-2016 --------
or more specifically, the whole path of this module
please note the type and color, it will affect the package name
package org.apache.spark.streaming.flume.sink;
I have a basic sbt project. I want to package two jars with the same source files, but compilation with different options.
So one project, 2 compilations but with different options (scalacOptions) and 2 jars as output. I don't want to execute sbt twice, changing the options.
Does anybody have an idea?
With something like this in build.sbt, you can run sbt compile2:package and produce both a jar from the compile config and compile2 config:
val Compile2 = config("compile2") extend Compile
inConfig(Compile2)(Defaults.compileSettings ++ Seq(
// these options can be set as "in Compile2" outside of inConfig as well
scalacOptions := SECOND-OPTIONS-LIST,
// otherwise it will be "src/compile2", you want it to be "src/main"
sourceDirectory <<= sourceDirectory in Compile,
sbt.Keys.`package` <<= sbt.Keys.`package` dependsOn (sbt.Keys.`package` in Compile)
))
scalacOptions in Compile := BASIC-OPTIONS-LIST
I guess this is relatively simple in terms of lines of code, but not quite so straightforward if one isn't intimately familiar with sbt.