We've been using the Eclipse #NonNull and #Nullable annotations in our code for a while.
We are now adding some Spring projects defined with Gradle to our system. These projects will share quite a bit of code with our standalone projects as well.
We are seeing a problem due the Eclipse annotations (being compile time checking) don't work when a Spring/Gradle project refers to the shared code via Gradle generated .jar file. Eclipse needs to have the source of the shared jar in order for the annotations to work. Attaching the source in the Eclipse project only works until you need to do a Gradle Refresh, as that rebuilds the eclipse .project and .classpath files.
It's also a problem that you have to explicitly rebuild the shared .jar each time you make a change to the shared code. It's not done automatically.
I haven't found a way to have the Spring/Gradle projects just use a 2nd source directory for the shared code, and not need to have the shared code as a generated .jar file.
Is there any good way to have shared code between multiple Gradle projects in Eclipse - without using an intermediate .jar file? (Or some other way to get the Eclipse annotations to work.)
Not really sure how to give a full example, as most of this is gradle and eclipse configuration.
Here are the Gradle config files: settings.gradle
pluginManagement {
repositories {
maven { url 'https://repo.spring.io/milestone' }
gradlePluginPortal()
}
}
rootProject.name = 'App1-Account-Manager'
and build.gradle
plugins {
id 'org.springframework.boot' version '2.5.0-RC1'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.efi'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation group: 'io.jsonwebtoken', name: 'jjwt', version: '0.2'
implementation 'org.springframework.boot:spring-boot-starter-amqp'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.amqp:spring-rabbit-test'
implementation files('lib/eflow/eFlowClientApi.jar',
'lib/eflow/eFlowCryptography.jar',
'lib/eflow/json-simple-1.1.1.jar',
'lib/eflow/commons-codec-1.4.jar',
'lib/eflow/commons-io-2.6.jar',
'lib/eflow/commons-lang-2.6.jar',
'lib/eflow/commons-logging-1.2.jar',
'../App1-Commons/build/libs/App1-Commons-0.0.1-SNAPSHOT.jar'
)
implementation group: 'org.eclipse.jdt', name: 'org.eclipse.jdt.annotation', version: '2.1.100'
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.7'
runtimeOnly 'org.postgresql:postgresql'
testImplementation 'org.springframework.security:spring-security-test'
}
test {
useJUnitPlatform()
}
App1-Commons is the project of shared code that multiple other projects depend on. That's where a bunch of the #NonNull annotations are.
I can set the App1-Account-Manager project to depend on the App1-Commons project in eclipse - but as soon as you run a Gradle Refresh, it looses that connection.
I'd prefer to just have the source from App1-Commons included in the App1-Account-Manager project - but I don't see how to configure Gradle to do that with Eclipse projects.
I think I found the solution. I need to add a SourceSets block to the build.gradle file like this:
sourceSets {
main {
java {
srcDir 'src/main/java'
srcDir '../App1-Commons/src/main/java'
}
}
}
And remove the reference to the App1-Commons jar file.
Related
This question already has answers here:
How to add a Maven project as a Gradle dependency?
(3 answers)
Closed 2 years ago.
I have created dependency jar using maven project but now i have to add this maven dependency into my gradle project.
Depencency available in my .m2 directory
Am getting the below error from intellij .
Execution failed for task ':compileJava'.
> Could not resolve all files for configuration ':compileClasspath'.
> Cannot convert URL 'com.example.auth.security:common:0.0.1-SNAPSHOT.jar' to a file.
Please find my build.gradle file
plugins {
id 'org.springframework.boot' version '2.1.16.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
id 'war'
}
group = 'com.example.auth'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
implementation files('com.example.auth.security:common:0.0.1-SNAPSHOT.jar') --> getting error on this line.
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
compileOnly 'org.projectlombok:lombok'
implementation('io.jsonwebtoken:jjwt:0.9.1')
}
Update 1
A problem occurred evaluating root project 'auth-center'.
> Supplied String module notation '0.0.1-SNAPSHOT' is invalid. Example notations: 'org.gradle:gradle-core:2.2', 'org.mockito:mockito-core:1.9.5:javadoc'.
You will need to add a local maven repository like this
repositories {
maven { url new File(pathToYourM2Directory).toURI().toURL() }
}
Additionally the declaration of the dependency is not correct. It should be
dependencies {
implementation group: 'com.example.auth.security', name: 'common', version '0.0.1-SNAPSHOT'
}
You can as well fix the files dependency. However using a local maven repo is more sustainable as by resolving artifacts this way it is transparent for the build process if an artifact is resolved locally or remote.
Can't comment since I don't have sufficient reputation. I believe you shouldn't be trying to add the maven dependency to the gradle project. Instead, host the maven dependency elsewhere and configure gradle to pull dependencies from there. For reference, you can take a look at this answer
How to add a Maven project as a Gradle dependency?
This is another way to import your custom java library(.jar).
What you need to do is that first, make a folder wherever you want under your project, in my case /src/lib, and put JAR file into that folder. Then, write down the below code into your Gradle file.
dependencies {
//Library Auto Implement
//Replace with your folder URI
implementation(fileTree("./src/lib"))
}
Then Gradle will implement your JAR files from that folder, and you are ready to go.
I tried using the 'api' dependency keyword in my project , but I got this error saying it cannot find method api()
I tried it on a new project. this is the build.gradle file:
plugins {
id 'java'
}
group 'com.test'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
api group: 'com.google.guava', name: 'guava', version: '27.0.1-jre'
}
I am using gradle V4.9.
when I run gradle build I get this:
Could not find method api() for arguments [{group=com.google.guava, name=guava, version=27.0.1-jre}] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler
If I replace 'api' with 'implementation' everything works fine
What am I missing here?
Is there any setting that needs to be done?
The api configuration comes from the java-library plugin, in your build script you have just applied java plugin. See https://docs.gradle.org/current/userguide/java_library_plugin.html
The key difference between the standard Java plugin and the Java Library plugin is that the latter introduces the concept of an API exposed to consumers. A library is a Java component meant to be consumed by other components. It’s a very common use case in multi-project builds, but also as soon as you have external dependencies.
Just apply the java-library plugin (which extends java plugin) and it should work:
plugins {
id 'java-library'
}
For those using kotlin build scripts use the following:
plugins {
id("org.gradle.kotlin.kotlin-dsl")
}
I have a java project made by some sibling modules. One of these modules is a library and I'm applying java-library plugin on it. All the other modules depend on it.
What I need to do is to automate the creation of a zip for each module, containing all the classes and all the dependencies needed for it to work (I'm deploying the zip as aws-lambda functions).
So far this is what I have achieved, but the resulting zip only contains module's classes. I thought that the problem might be the type of dependency I'm using (implementation) and I tried switching to the default one but gradle doesn't even success in building.
apply plugin: 'java'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
task buildZip(type: Zip) {
from compileJava
from processResources
from configurations.runtime
}
dependencies {
implementation project(':utils')
testCompile group: 'junit', name: 'junit', version: '4.12'
}
After some testing, I think I have the answer.
First: the order you declared the task and the dependencies is fine! It's OK to use a configuration before it's populated. I only say this because I indicated in my comments that it might be an issue.
Second, the issue here is the use of configurations.runtime. This does not extend implementation and api, so those dependencies are not included. runtime has been superseded by runtimeOnly, which hopefully makes the behaviour clear.
The following task definition should work:
task buildZip(type: Zip) {
from compileJava
from processResources
from configurations.runtimeClasspath
}
I'm trying to run ./gradlew build for a nested multi project structure and I'm running into issues that only seem to appear for projects with test source roots. Being new to both java and gradle I'm sure I'm breaking more than one convention, but I still think this should be working.
Essentially, all the dependencies seem to be added fine, but when I have one project that only has a Test srcDir that depends on another project that has a Test srcDir, it doesn't recognize packages/symbols in that root project. However, projects with regular srcDirs (not test) don't seem to have a problem.
My project has more going on than this, but here is the simplest setup I've tried that illustrates the problem.
My project structure:
qatests
/Applications
/AppGroupName
/AppBasePageObjects
/src
/AppBaseTests
/src
/BasePageObjects
/src
/BaseTests
/src
My settings.gradle in qatests:
rootProject.name = 'QaTests'
include 'BasePageObjects'
include 'BaseTests'
include 'Applications:AppGroupName'
include 'Applications:AppGroupName:AppBasePageObjects'
include 'Applications:AppGroupName:AppBaseTests'
My build.gradle in qatests:
version '1.0-SNAPSHOT'
allprojects {
repositories {
mavenCentral()
}
}
subprojects{
if(project.name.contains("Tests")){
apply plugin: 'java'
sourceCompatibility = 1.8
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.11'
compile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '2.+'
}
if(project.name != "BaseTests")
{
println "$project.name depends on BaseTests"
dependencies {
testCompile project(':BaseTests')
}
}
sourceSets {
test {
java {
srcDir 'src'
}
}
}
}
if(project.name.contains("PageObjects")){
apply plugin: 'java'
sourceCompatibility = 1.8
dependencies {
compile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '2.+'
}
if(project.name !="BasePageObjects")
{
dependencies {
compile project(':BasePageObjects')
}
}
sourceSets {
main {
java {
srcDir 'src'
}
}
}
}
}
I won't include my build.grade for the BaseTest project since that seems to compile fine during the gradlew build, but here is my build.gradle for AppBaseTests:
version '1.0-SNAPSHOT'
dependencies {
compile 'org.apache.commons:commons-lang3:3.4'
compile project(':Applications:AppGroupName:AppBasePageObjects')
}
When I run ./gradlew build in the qatests root, the BaseTests, BasePageObjects, and AppBasePageObjects projects seem to compile fine and AppBasePageObjects successfully uses packages and symbols from BasePageObjects. For some reason however, AppBaseTests can't seem to recognize packages and symbols in BaseTests.
If I clone this project from scratch, IntelliJ runs the gradle scripts scripts automatically and everything seems to work out of the box just fine with the dependencies, so this just confuses me even more.
I've tried adding compile and testcompile for all the project dependencies since that's the only real difference between AppBasePageObjects which works and AppBaseTests which doesn't work. I've also tried adding compileJava.dependsOn(':BaseTests:build') to the AppBaseTests build.gradle file. And a few other rabbit holes, but nothing seems to have any effect on this dependency issue.
For what it's worth, here is the first error I see in the actual build:
error: package Tests does not exist import Tests.BaseTest;
Any help or suggestions are greatly appreciated. If you would like to distribute some harsh insults I'll take those as well. Thank you.
I believe I found an answer while reading another solution here:
Multi-project test dependencies with gradle
It seems I needed to use testCompile project(':BaseTests').sourceSets.test.output for command line builds as well as testCompile project(':BaseTests') for IDE functionality in my root build.gradle file. This only seems to be required for the test projects.
Here are the actual changes in my root build.gradle file:
if(project.name != "BaseTests")
{
println "$project.name depends on BaseTests"
dependencies {
testCompile project(':BaseTests')
testCompile project(':BaseTests').sourceSets.test.output
}
}
This seems a bit hacky but works, if somebody has a more thorough and intelligent answer please post!
I'm starting with Gradle and I was wondering how do I include a single dependency (TeamSpeak API in my case) into my JAR so that it could be available at the runtime.
Here is a part of my build.gradle :
apply plugin: 'java'
compileJava {
sourceCompatibility = '1.8'
options.encoding = 'UTF-8'
}
jar {
manifest {
attributes 'Class-Path': '.......'
}
from {
* What should I put here ? *
}
}
dependencies {
compile group: 'org.hibernate', name: 'hibernate-core', version: '4.3.7.Final'
compile group: 'org.spigotmc', name: 'spigot', version: '1.8-R0.1-RELEASE'
// Many other dependencies, all available at runtime...
// This one isn't. So I need to include it into my JAR :
compile group: 'com.github.theholywaffle', name: 'teamspeak3-api', version: '+'
}
Thanks for your help :)
The easiest way is to start with a separate configuration for the dependencies you want to include. I know you only asked about a single jar but this solution will work if you add more dependencies to your new configuration. Maven has a well known name for this sort of thing called provided, so that is what we will use.
configurations {
provided
// Make compile extend from our provided configuration so that things added to bundled end up on the compile classpath
compile.extendsFrom(provided)
}
dependencies {
provided group: 'org.spigotmc', name: 'spigot', version: '1.8-R0.1-RELEASE'
}
jar {
// Include all of the jars from the bundled configuration in our jar
from configurations.provided.asFileTree.files.collect { zipTree(it) }
}
Using provided as the name of the configuration is also important because when the jar gets published, any dependencies you have in the providedconfiguration will show up as provided in the POM.xml that gets published with the JAR. Maven dependency resolvers will not pull down provided dependencies and users of your jar will not end up with duplicate copies of classes on the classpath. See Maven Dependency Scopes