Why gradle's buildscript classpath doesn't contain buildSrc? - gradle

i can't see buildSrc on the buildscript classpath in gradle; i can access it...but it somehow isn't there
i expected that it's there...because the buildscript can use those classes
build.gradle:
apply plugin: 'java'
buildscript{
dependencies{
classpath gradleApi()
}
}
task show(){
A.asd()
buildscript.configurations.classpath.each { println it }
}
contents of: buildSrc/src/main/java/A.java
public class A{
public static void asd(){
System.out.println(A.class + " is invokable from"+A.class.getProtectionDomain().getCodeSource().getLocation().getPath());
}
}
output:
:buildSrc:clean
...
:buildSrc:build
class A is invokable from/home/kirk/projects/bt/ews/tx3/buildSrc/build/classes/main/
/home/kirk/tools/gradle-1.11/lib/gradle-core-1.11.jar
...other nonrelated jars/etc
:show

buildscript { dependencies { classpath ... } } is the way to explicitly add build script dependencies. The buildSrc output directory is added implicitly.

Related

Kotlin Gradle Could not find or load main class

I tried to copy the Spring Boot Kotlin sample project https://github.com/JetBrains/kotlin-examples/tree/master/tutorials/spring-boot-restful. I Added some more dependencies and when I tried to build the executable jar and run it, I got the error:
Could not find or load main class...
Gradle build script:
buildscript {
ext.kotlin_version = '1.1.3' // Required for Kotlin integration
ext.spring_boot_version = '1.5.4.RELEASE'
repositories {
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // Required for Kotlin integration
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version" // See https://kotlinlang.org/docs/reference/compiler-plugins.html#kotlin-spring-compiler-plugin
classpath "org.springframework.boot:spring-boot-gradle-plugin:$spring_boot_version"
}
}
/*plugins {
id 'org.springframework.boot' version '2.0.0.RELEASE'
}*/
apply plugin: 'kotlin' // Required for Kotlin integration
apply plugin: "kotlin-spring" // See https://kotlinlang.org/docs/reference/compiler-plugins.html#kotlin-spring-compiler-plugin
apply plugin: 'org.springframework.boot'
jar {
baseName = 'gs-rest-service'
version = '0.1.0'
from {
(configurations.runtime).collect {
it.isDirectory() ? it : zipTree(it)
}
}
manifest {
attributes 'Main-Class': 'org.jetbrains.kotlin.demo.Applicationkt'
}
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin/'
test.java.srcDirs += 'src/test/kotlin/'
}
repositories {
jcenter()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" // Required for Kotlin integration
compile("org.springframework.boot:spring-boot-starter-web")
compile group: 'org.apache.camel', name: 'camel-quartz2', version: '2.20.2'
compile group: 'org.apache.camel', name: 'camel-http4', version: '2.20.2'
compile group: 'org.apache.camel', name: 'camel-docker', version: '2.20.2'
compile group: 'org.apache.camel', name: 'camel-aws', version: '2.20.2'
testCompile('org.springframework.boot:spring-boot-starter-test')
}
Change Applicationkt to ApplicationKt will work, and BTW you may upgrade Kotlin version to 1.3.50.
By Applicationkt I mean the one in this line:
attributes 'Main-Class': 'org.jetbrains.kotlin.demo.Applicationkt'
Kotlin compiles the Application file in two different files:
one file called Application.class with the Springboot things
another file called ApplicationKt.class with the main method
In this second file is where the main function is located at, so you have to use this name in the build.gradle file.
mainClassName = 'org.jetbrains.kotlin.demo.ApplicationKt'
Update your build.gradle to
jar {
manifest {
attributes 'Main-Class': 'org.jetbrains.kotlin.demo.ApplicationKt'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
with an upper case K in ApplicationKt.
This is required because of the way Kotlin compiles to Java Bytecode. The fun main() function in Kotlin is not attached to any class, but Java always requires a class and does not support classless functions.
The Kotlin compiler has to create a Java class. Because you already defined a class Application it created one with the suffix Kt for the functions in your Kotlin file org/jetbrains/kotlin/demo/Application.kt. You have to set this class so that the JVM can find it.
BTW a Jar file is just a Zip file, you can unpack it and see for yourself if the ApplicationKt.class is there.
For me the main function needed to be outside the class body
#SpringBootApplication
#Configuration
class Application
(private val locationRepository: LocationRepository,
) : CommandLineRunner {
override fun run(vararg args: String?) {
whatever()
}
}
fun main(args: Array<String>) {
runApplication<Application>(*args)
}
Indeed, Kotlin create file ApplicationKt.class in the jar if your main class file is named Application.kt. You have to add the following lines:
apply plugin: 'kotlin'
apply plugin: 'application'
mainClassName = 'org.jetbrains.kotlin.demo.ApplicationKt'
If you use the classic jar plugin, you can do as below (which is described in previous responses):
jar {
manifest {
attributes 'Main-Class': 'org.jetbrains.kotlin.demo.ApplicationKt'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
However, my preference is to use bootJar plugin which is much clear and which allow me to use layered jars for example:
bootJar {
layered() // Not useful if you don't want to use layered jars
}

gradle plugin dependencies not found under buildSrc

I have a working build.gradle that I'd like to refactor into the buildSrc directory but I'm having trouble finding the dependencies.
Working build.gradle:
import groovyx.net.http.HTTPBuilder
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath 'org.codehaus.groovy.modules.http-builder:http-builder:0.7.2'
}
}
plugins {
id 'groovy'
}
group "com.example"
version "0.0.1"
class Foo {
Foo() {
new HTTPBuilder('http://www.example.com')
}
}
Non-working refactored build.gradle:
However, when I try to split into the following:
build.gradle
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath 'org.codehaus.groovy.modules.http-builder:http-builder:0.7.2'
}
}
plugins {
id 'groovy'
}
group "com.example"
version "0.0.1"
and buildSrc/src/main/groovy/Foo.groovy
import groovyx.net.http.HTTPBuilder
class Foo {
Foo() {
new HTTPBuilder('http://www.example.com')
}
}
Gives the error:
C:\Project\buildSrc\src\main\groovy\Foo.groovy: 7: unable to resolve
class HTTPBuilder # line 5, column 26.
HTTPBuilder client = new HTTPBuilder('http://www.example.com')
How can I get gradle to recognise the dependencies?
You need to create a build.gradle file for buildSrc directory. Try this:
C:\Project\buildSrc\build.gradle
apply plugin: 'groovy'
repositories {
mavenCentral()
jcenter()
}
dependencies {
compile 'org.codehaus.groovy.modules.http-builder:http-builder:0.7.2'
}
There is more details in this documentation section.

Why do I need to specify 'from files'?

I was trying to build a jar out of my first groovy script. My project structure is as follows:
- build.gradle
- src\main\groovy\app\Test.groovy
My original gradle script:
apply plugin: 'groovy'
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.3.11'
testCompile group: 'junit', name: 'junit', version: '4.11'
}
sourceSets.main.groovy.srcDirs = ["src/main/groovy"]
jar {
manifest {
attributes('Main-Class': 'app.Test')
}
}
From the guides I read, this should create a runnable jar. When I try to run it though I always get the error
Error: Could not find or load main class app.Test
I found out now that I need to add these two lines to the jar task:
from files(sourceSets.main.output.classesDir)
from configurations.runtime.asFileTree.files.collect { zipTree(it) }
The weird thing is that if I replace the groovy script with a Test.java class (same content), I don't need those two extra lines to run the jar.
I couldn't find out why I need them or what exactly they do. Can anyone explain that, or offer a documentation link?
I'm new to SO, please help me with my mistakes.
EDIT
The code suggested by tim_yates is translated to test.jar with the following content:
META-INF/MANIFEST.MF
Manifest-Version: 1.0
Main-Class: app.Test
app/Test.class
package app;
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.callsite.CallSite;
public class Test implements GroovyObject {
public Test() {
CallSite[] var1 = $getCallSiteArray();
MetaClass var2 = this.$getStaticMetaClass();
this.metaClass = var2;
}
public static void main(String... args) {
CallSite[] var1 = $getCallSiteArray();
var1[0].callStatic(Test.class, "Hi!");
}
}
I execute with the following statement:
java -jar test.jar
Which results in the error message stated above.
You've got to remember that this jar contains Groovy compiled classes. The answer is in your decompiled source that you showed in the beginning. It imports Groovy runtime classes.
If you just run java -jar test.jar those classes are not on the classpath.
Either include groovy on the classpath of your command line or use the gradle application plugin to build a fat JAR (which is probably better for runnable jars) that contain all your application dependencies.
apply plugin: 'groovy'
apply plugin: 'application'
mainClassName='app.Test'
repositories {
mavenCentral()
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.4.7'
testCompile 'junit:junit:4.12'
}
task uberjar(type: Jar,dependsOn:[':compileJava',':compileGroovy']) {
from files(sourceSets.main.output.classesDir)
from configurations.runtime.asFileTree.files.collect { zipTree(it) }
manifest {
attributes 'Main-Class': mainClassName
}
}
Then build your jar with gradle uberjar
Assuming Test.groovy looks something like:
package app
class Test {
static main(args) {
println "Hi!"
}
}
Then you only need the following build script:
apply plugin: 'groovy'
repositories {
mavenCentral()
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.4.7'
testCompile 'junit:junit:4.12'
}
jar {
manifest {
attributes('Main-Class': 'app.Test')
}
}

How to load Gradle Plugin (with its depenecies) into build.gradle?

I have a project that has two gradle files: build.gradle and myPlugin.gradle
The myPlugin.gradle implemented the Plugin Interface. The plugin also has a dependency on osdetector-gradle-plugin
I added the two gradle files beside each other then I tried to apply myPlugin into build.gradle as follows:
apply from: 'myPlugin.gradle'
However, I have got the following error in myPlugin.gradle file:
Plugin with id 'com.google.osdetector' not found
Here is the code for myPlugin.gradle file:
apply plugin: 'groovy'
apply plugin: 'maven'
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
compile 'com.google.gradle:osdetector-gradle-plugin:1.4.0'
}
import org.gradle.api.tasks.TaskAction
import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
import org.gradle.api.Project
apply plugin: 'com.google.osdetector'
apply plugin: HostingMachineOSPlugin
class HostingMachineOSPlugin implements Plugin<Project>{
void apply(Project project){
project.plugins.apply("com.google.osdetector");
//project.configurations.files('com.google.osdetector')
println project.osdetector.os
/* Extend the project property to have the class HostingMachineOS */
project.ext.HostingMachineOS = HostingMachineOS
}
}
public class HostingMachineOS {
static family = "Unkown"
static def setFamilyName(name){
family = name
}
static def isLinux (){
family == "linux"
}
static def isWindows (){
family == "windows"
}
static def isMacOS(){
family == "osx"
}
}
HostingMachineOS.setFamilyName(osdetector.os)
in build.gradle file: I am just doing something like this:
//define buildScript repositories and dependencies then
apply from: 'myPlugin.gradle'
task dummy{
println HostingMachineOS.isMacOS()
println HostingMachineOS.isLinux()
println HostingMachineOS.isWindows()
}
How can I solve the Plugin with id 'com.google.osdetector' not found?
This is a common pitfall, to add a plugin to build.gradle file you need to add a dependency for the build script itself - not for the project. The following piece of code (added in the file where you apply the plugin) should solve the problem:
buildscript {
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
classpath 'com.google.gradle:osdetector-gradle-plugin:1.4.0'
}
}
EDIT
Please have a look here - it seems that if you need to apply from third-party script you need to use the full class name (with package). So the files should be defined as follows:
build.gradle
apply from: 'myPlugin.gradle'
task dummy{
println HostingMachineOS.isMacOS()
println HostingMachineOS.isLinux()
println HostingMachineOS.isWindows()
}
myPlugin.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.google.gradle:osdetector-gradle-plugin:1.4.0'
}
}
apply plugin: 'groovy'
apply plugin: 'maven'
apply plugin: com.google.gradle.osdetector.OsDetectorPlugin
apply plugin: HostingMachineOSPlugin
class HostingMachineOSPlugin implements Plugin<Project>{
void apply(Project project){
project.plugins.apply(com.google.gradle.osdetector.OsDetectorPlugin);
//project.configurations.files('com.google.osdetector')
println project.osdetector.os
/* Extend the project property to have the class HostingMachineOS */
project.ext.HostingMachineOS = HostingMachineOS
}
}
public class HostingMachineOS {
static family = "Unkown"
static def setFamilyName(name){
family = name
}
static def isLinux (){
family == "linux"
}
static def isWindows (){
family == "windows"
}
static def isMacOS(){
family == "osx"
}
}
HostingMachineOS.setFamilyName(osdetector.os)

gradle war: how to force inclusion of transitively provided dep?

Having this build.gradle:
apply plugin: 'war'
repositories {
mavenCentral()
maven { url "http://repository.jboss.org/nexus/content/groups/public" }
}
configurations {
providedCompile {
exclude module: 'commons-httpclient' // here it doesn't work
}
}
dependencies {
compile 'commons-httpclient:commons-httpclient:3.1'
providedCompile ('org.jboss.resteasy:resteasy-jaxrs:2.3.3.Final') {
//exclude module: 'commons-httpclient' // here it works
}
}
I expect to have this war:
WEB-INF/
WEB-INF/lib/
WEB-INF/lib/commons-httpclient-3.1.jar
but only have this:
WEB-INF/
If I un-comment 2nd exclude and comment 1st exclude, it works as needed.
If this is expected behavior, how can I otherwise globally exclude a particular transitive from provided libs?
It turns out that this is the "right" thing to happen, as compile actually extends from providedCompile:
apply plugin: 'war'
configurations.compile.extendsFrom.each {
println "$it"
}
So, my solution was the following:
apply plugin: 'war'
repositories {
mavenCentral()
maven { url "http://repository.jboss.org/nexus/content/groups/public" }
}
configurations {
forceInclude {}
}
dependencies {
providedCompile 'org.jboss.resteasy:resteasy-jaxrs:2.3.3.Final'
forceInclude 'commons-httpclient:commons-httpclient:3.1'
}
war {
classpath += configurations.forceInclude
}

Resources