Generated tests fail in Spring Cloud Contract - java

I am new to spring-cloud-contract. Just trying to configure my build and I am getting error.
Here is my project structure
Project
| ==> Module
I have the following dependencies for classpath in my project build.gradle
Project Build file
buildscript {
dependencies {
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.2.1"
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE")
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:1.1.3.RELEASE"
}
apply from: "$projectDir/gradle/app/springcloud.gradle" //Gradle build file in module
}
Module Build file
apply plugin: 'groovy'
apply plugin: 'spring-cloud-contract'
apply plugin: 'org.springframework.boot'
dependencies {
//Spring cloud contract dependencies
compile('org.springframework.boot:spring-boot-starter-actuator')
compile('org.springframework.boot:spring-boot-starter-web')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('org.springframework.cloud:spring-cloud-starter-contract-verifier')
testCompile "org.springframework.cloud:spring-cloud-starter-contract-stub-runner"
testCompile "com.jayway.restassured:rest-assured:2.5.0"
testCompile "com.jayway.restassured:spring-mock-mvc:2.5.0"
}
//Spring cloud contract dependency management
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:Dalston.RELEASE"
}
}
I have a groovy file which has a post request and a response. When I do gradle build, the tests are autogenerated but my build is feeling.
C:\Users\user\Projects\myProject\module\build\generated-test-sources\contracts\org\springframework\cloud\contract\verifier\tests\ContractVerifierTest.java:3: error: cannot find symbol
import com.jayway.jsonpath.DocumentContext;
^
symbol: class DocumentContext
location: package com.jayway.jsonpath
C:\Users\user\Projects\myProject\module\build\generated-test-sources\contracts\org\springframework\cloud\contract\verifier\tests\ContractVerifierTest.java:28: error: cannot find symbol
DocumentContext parsedJson =
JsonPath.parse(response.getBody().asString());
^
Am I doing something wrong? Is there any mismatch in the versions which I am using?

#Marcin Thanks for your inputs. This is how I solved this issue.
The build fails inside generated tests and jayway jsonpath is not showing in Red colour at the position of error. When I Ctrl + Hover (mouse) on the import it's referencing to com.jayway.jsonpath:json-path:2.2.0 which is not true. The reason is because I have imported many modules in Intellij and apparently one of the module also imports 2.2.0 and intellij is referencing it from external library.
So I did invalidate cache intellij and closed all unnecessary projects and reopened the project alone which I am working on, in a new window (Fresh session). Now gradle build and again I got the same error on the generated tests. But this time When I Ctrl + Hover (mouse) on the import its refering to the com.jayway.jsonpath:json-path:0.9.1 which is what I am expecting.
Now to solve this issue, I've examined the dependency tree using the below command and did some grep on it.
allDeps --configuration testRuntime
I found the answer, why gradle is replacing 2.2.0 with 0.9.1. I've figured out some project dependency is replacing it. Now the solution for this is modifying my module build file for jayway json-path as shown below. After that I've given build gradle command and now the errors are gone.
testCompile ('com.jayway.jsonpath:json-path:2.2.0') {
force = true
}
And finally, I've got exception saying that SpringCloudContractAssertions unable to find.
org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat;
So I replace Camden release with Dalston as shown below. Now it all works fine.
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:Dalston.RELEASE"
}
}

Related

Gradle dependencies: package does not exist

I know this has been asked multiple times but the questions have multiple answers.
I'm trying to use a Java package that's a dependency of my dependency. Let's say I've built this gradle project called "ee_tools". And that has a dependency called "my_models", which has a package called "com.mycompany.my_models.db". So in the ee_tools project build.gradle, I've got
dependencies {
// My stuff
implementation group: "com.mycompany", name: "my_models", version: "1.0.0"
}
Then in my current project, I've got
dependencies {
// My stuff
implementation group: "com.mycompany", name: "ee_tools", version: "1.0.0"
Shouldn't this mean that the public classes in my_models are accessible through ee_tools to my current project? Gradle was able to find both in my artifactory instance. And the gradle dependencies command shows ee_tools under the compileClasspath, implementation, and testCompileClasspath trees, but not with its children dependencies. It also shows up in the runtimeClasspath and testRuntimeClasspath trees with its children dependencies, including my_models.
I am also able to see that package inside the jar on the left side of IntelliJ, under the "External Libraries" tree, along with some classes.
But when I try to use the my_models package in my current project, IntelliJ can't find it and it fails a gradle build with the error
error: package com.company.my_models.db does not exist
It can't find any package in that dependency. What gives? Am I declaring the dependencies incorrectly? Or is this a gap between the gradle binary in my command line vs IntellJ and gradlew?
If ee_tools depends on my_models, then your gradle file in ee_tools should be like
implementation project(path: ":path:to:my_models", configuration: 'default')
:path:to:my_models is defined in settings.gradle in project root path like this:
include ':path:to:my_models'

How to solve error: package org.springframework.context.annotation does not exist import org.springframework.context.annotation.Bean?

After updating the gradle wrapper to version 7.3.2 I get the following error when trying to build my spring boot project:
error: package org.springframework.context.annotation does not exist
import org.springframework.context.annotation.Bean;
Why is this happening?
Update:
Found the problem, but do not know how to fix yet.
I have multiple modules in my project. I have a "common" module which is used by other modules. With the old gradle version the libs of the common project were added to the compileClasspath of other modules, with the new version it adds them only to the runtimeClasspath.
The dependencies used to be declared as compile, now with gradle 7+ I had to change them to implementation.
Any suggestions?
In other module:
dependencies {
implementation project(':common')
...
}
In common module:
dependencies {
implementation spring.web
...
}
I think you have an issue with transitivity , if you use java-library instead of java plugin
plugins {
id 'java-library'
}
https://docs.gradle.org/current/userguide/java_library_plugin.html#java_library_plugin
then you can use the api instead of compile which can help
you can see a good explanation What's the difference between implementation, api and compile in Gradle?

How to put local dependencies first when calling gradle idea?

When calling gradle idea, external dependencies are ordered first in the class path relatively to local Jar inclusions. As such :
dependencies {
compile fileTree(dir: 'libs', include:['*.jar'])
compile group: 'foo', name:'bar', version:'1.0.0'
}
will include my local jars last. This is a problem in my project as these jars' purpose is to partially overwrite the external library.
The same behavior is observed when specifying the repository as a source of dependencies using flatDir and loading the jar without fileTree. It is put last in the classpath.
I have found several mentions of the problem when researching, such as https://discuss.gradle.org/t/gradle-messes-up-the-classpath-order-in-generated-projects-when-there-are-mixed-dependency-types/13130, but no workarounds.
I suppose these exist, gradle being very customisable, but being very new to it my attempts to make one fail. How to proceed?
I'm not using IntelliJ on a regular basis but tried it in the context of this question and my impression is that gradle's idea plugin and IntelliJ's gradle plugin don't go well together. That is you should either use the idea gradle plugin and import as plain Java project or import as gradle project using IntelliJ's gradle plugin. Main reason is that the idea plugin and the IntelliJ plugin are generating slightly different iml-files (those files are holding the project dependencies - amongst others) which leads to lot of confusion when using both plugins together. As you specifically asked for the gradle idea plugin, I used this plugin and imported into IntelliJ as plain java project.
But to answer your question I found no evidence that the order of libraries on the classpath differs from the order as declared in the dependencies section of the gradle file, when using a flatDir repo. When using compile fileTree(dir: 'libs', include:['*.jar']) the order was actually broken as described in your question. That is, you should stick to using a flatDir repo.
I'm using gradle 4.9 and IntelliJ 2018.2.
This is my gradle file
apply plugin: 'java'
apply plugin: 'idea'
repositories {
jcenter()
flatDir {
dirs 'libs'
}
}
dependencies {
compile 'zzz:zzz-0.0.0'
compile 'aaa:aaa-0.0.0'
compile 'com.google.guava:guava:24.0-jre'
compile group: 'javax.websocket', name: 'javax.websocket-api', version: '1.1'
}
task wrapper(type: Wrapper) {
gradleVersion = '4.9'
distributionUrl = "http://services.gradle.org/distributions/gradle-${gradleVersion}-bin.zip"
}
In my libs folder there are two jars aaa-0.0.0.jar and zzz-0.0.0.jar both are copies of guava-24.0-jre.jar. That is all guava classes are present in both jars as well. As zzz:zzz-0.0.0 is the first dependency in the gradle file, the expectation would be that guava classes are being loaded from zzz-0.0.0.jar instead of guava-24.0-jre.jar or aaa-0.0.0.jar. I used the following main class to test this:
package test;
import com.google.common.math.LongMath;
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(LongMath.class.getProtectionDomain().getCodeSource().getLocation().toURI());
}
}
And the output when running it from IntelliJ is
file:/C:/ws/gradle-idea-test/libs/zzz-0.0.0.jar
That is the com.google.common.math.LongMath class is indeed being loaded from the local libs/zzz-0.0.0.jar instead of the guava-24.0-jre.jar.
I noticed that the list of external dependencies in IntelliJ doesn't show the local libraries. And even more confusing the libraries are ordered alphabetically and don't reflect the actual order on the classpath which might be quite confusing:
To get the actual order of elements on the classpath you will have to look in the module dependencies section in the module settings ("Open Module Settings" > "Project" > "Modules" > "Dependencies Tab") which looks like this:
As you can see the dependencies are listed in correct order and include the local libraries as well. The order of libs in this dialog is basically the same as in the generated iml-file.
When using the IntelliJ gradle plugin instead of gradle's idea plugin, IntelliJ basically behaved the same way but the generated iml-file looked different and the external libraries were displayed in a different format. But there was no difference regarding the classpath order.

intellij build jar artifact containing gradle dependencies

I basically want to do something simple - or atleast i think it should be pretty simple.
My goal is to create an Intellij gradle project, add some dependencies to the module using gradle and add some java source code to it.
Then I just want to have an option to somehow compile the whole thing into 1 jar, containing all grade dependencies and being able to execute using "java -jar"
However it turned out that this is not as easy is i had thought.
I just created a new gradle project from intellij and added a Main class.
I´ll give you an overview over my files:
settings.gradle:
rootProject.name = 'gradleTestNewJar'
build.gradle:
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'application'
sourceCompatibility = 1.6
version = '1.0'
repositories {
mavenCentral()
}
mainClassName = "com.randomPackage.StarterClass"
dependencies {
compile 'org.seleniumhq.selenium:selenium-java:2.46.0'
testCompile group: 'junit', name: 'junit', version: '4.11'
}
main class:
package com.randomPackage;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
public class StarterClass {
public static void main(String[] args){
System.out.println("test");
WebDriver driver = new HtmlUnitDriver(BrowserVersion.FIREFOX_38);
driver.quit();
}
}
The main method of "MyStart" is executed when running from Intellij via debug.
So it works, when all dependencies get loaded correctly.
NOTE: I use Intellij Community Edition if this makes any difference.
What i tried:
1. I tried to just use "gradlew clean build".
This created a jar, but without libs.
But I didn´t expect it to be as easy as this.
2. I tried to build an artifact of the module as suggested here:
http://blog.jetbrains.com/idea/2010/08/quickly-create-jar-artifact/
I tried it with extracted and not extracted dependencies.
In both cases the dependencies were added into the jar, but they were added to the root of the jar.
When i tried to run the jar file via "java -jar", it complained:
"Exception in thread "main" java.lang.NoClassDefFoundError: org/openqa/selenium/WebDriver
..."
OK, so it couldn´t load the dependencies.
NOTE: I thought that the dependencies were not added to the classpath, but i am not sure about this. However, i would expect Intellij to add dependencies to the classpath( or declare in the manifest file)
3. I also tried to use the gradle application plugin.
However this creates a zip/tar which contains a execute script and a bin folder which was not my intention.
So i started googling for hours and hours but i cann´t find a solution to my problem.
Come on this cannot be so hard - it is just so basic.
I am sure some genius can help me out and point me to my - probably stupid - failure.
My current solution is as follows:
I use gradle to build a jar containing all libs, I do this witha custom task called fatJar.
Here is a part from my build.gradle
apply plugin: 'java'
jar {
manifest {
attributes("Manifest-Version": "1.0",
"Main-Class": "com.randomPackage.MainClass");
}
}
task fatJar(type: Jar) {
manifest.from jar.manifest
classifier = 'all'
from {
configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) }
} {
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
}
with jar
}
Then I just execute "gradle fatJar" on the command line and get a perfect jar.

Dependencies of subproject can not be resolved for dependent project (but are resolved when building subproject itself)

Following the explanation in "Building and Testing with Gradle" I have a multiproject gradle setup like this:
rootFolder
build.gradle
settings.gradle
EMS
build.gradle
cloud-sdk
build.gradle
The cloud-sdk project depends on several jars, partially resolved via maven partially via locale jars:
// file: cloud-sdk/build.gradle
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
compile group:'org.apache.tomcat', name:'tomcat-catalina', version:'7.0.47'
compile group:'org.mongodb', name:'mongo-java-driver', version:'2.11.3'
compile group:'com.google.code.gson', name:'gson', version:'2.2.4'
compile group:'com.thoughtworks.xstream', name:'xstream', version:'1.4.6'
compile fileTree(dir:'lib/', include:'JavaPNS_2.2.jar')
compile fileTree(dir:'lib/', include:'gcm-server.jar')
}
The EMS-project depends on the cloud-sdk which I think should be defined like this:
// file: EMS/build.gradle
apply plugin: 'java'
dependencies {
compile project(':cloud-sdk')
}
Furthermore, my root build.gradle and settings.gradle files look like this:
settings.gradle
include 'cloud-sdk', 'EMS'
build.gradle
apply plugin: 'java'
dependencies {
compile project(':EMS')
}
In this case I am not sure whether I also need the dependency compile project (':cloud-sdk'). I tried both version but since I get the same error message in both cases I assume it doesn't matter.
When I try to run the script from the rootFolder via gradle build I get the following error messages:
Could not resolve all dependencies for configuration ':EMS:compile'.
> Could not find org.apache.tomcat:tomcat-catalina:7.0.47.
Required by:
rootFolder:EMS:unspecified > rootFolder:cloud-sdk:unspecified
> Could not find org.mongodb:mongo-java-driver:2.11.3.
Required by:
rootFolder:EMS > rootFolder:cloud-sdk:unspecified
> Could not find com.google.code.gson:gson:2.2.4.
Required by:
rootFolder:EMS > rootFolder:cloud-sdk:unspecified
> Could not find com.thoughtworks.xstream:xstream:1.4.6.
Required by:
rootFolder:EMS:unspecified > rootFolder:cloud-sdk:unspecified
But when I just build the cloud-sdk project via gradle cloud-sdk:build gradle downloads the required jars and builds the project without a problem.
But even if I try gradle build after that, although gradle notices that the cloud-sdk project is already up-to-date, it complains about the missing dependencies.
Why is that? It downloaded them already so they should be available somewhere and even if not the cloud-sdk knows what it needs and how to fetch it. What am I missing? Do I need to specify the dependencies in some other way?
Ok, it turns out gradle could not fetch the dependencies in the EMS project since I did not specify any repositories to fetch them from. I assumed that would not be necessary since the only dependencies I needed it to fetch were declared in the cloud-sdk project and that did have a repository given.
This is basically the solution to my problem, but if anybody can explain to me why it is necessary to specify the repository again or explain why it is a bug in gradle that should be fixed, I'll accept that answer as it would answer the "why" and not just the "how do I get it to work".

Categories