So we're trying trying to execute individual test cases in IntelliJ. Because we are using the jackson-module-parameter-names module, we must compile our project using the -parameters flag. All test cases are working fine when we execute them through Gradle, but when we run an individual test in IntelliJ, they are not working (because of the missing -parameters argument.
When running through intellij all the tests depending on jackson serialization are failing.
How does one fix this?
We already tried to make it work by setting the following setting in intellij to -parameters
Settings > Build, Execution, Deployment > Compiler > Java Compiler > Additional command line parameters
In gradle we have a similar setting which does work.
subprojects {
tasks.withType(JavaCompile) {
options.compilerArgs << '-parameters'
}
}
Related
I am using gradle-2.8 version due to organisation restrictions.
I am trying to read YAML file (OpenAPI - swagger specification) using the following code :
new OpenAPIParser().readLocation(urlString, null, parseOptions).getOpenAPI();
which is present in both the main and test sourceSets as it is.
I have defined 2 configurations
swagConfig (for compile time dependencies)
swagRuntime (for runtime dependencies)
where swagRuntime consists of the following dependencies :
'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.12.1'
'com.fasterxml.jackson.core:jackson-databind:2.12.1'
'com.fasterxml.jackson.core:jackson-core:2.12.1'
'com.fasterxml.jackson.core:jackson-annotations:2.12.1'
and the build.gradle includes the following :
configurations {
compile.extendsFrom swagConfig
runtime.extendsFrom swagRuntime
runtime {
resolutionStrategy {
force 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.12.1'
force 'com.fasterxml.jackson.core:jackson-databind:2.12.1'
force 'com.fasterxml.jackson.core:jackson-core:2.12.1'
force 'com.fasterxml.jackson.core:jackson-annotations:2.12.1'
}
}
testRuntime {
resolutionStrategy {
force 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.12.1'
force 'com.fasterxml.jackson.core:jackson-databind:2.12.1'
force 'com.fasterxml.jackson.core:jackson-core:2.12.1'
force 'com.fasterxml.jackson.core:jackson-annotations:2.12.1'
}
}
}
However, when I execute my main source-Set code, it works perfectly fine but when I run my test sourceSet based JUnit Test, I am running into failure :
java.lang.NoSuchMethodError: org.yaml.snakeyaml.events.ScalarEvent.<init>(Ljava/lang/String;Ljava/lang/String;Lorg/yaml/snakeyaml/events/ImplicitTuple;Ljava/lang/String;Lorg/yaml/snakeyaml/error/Mark;Lorg/yaml/snakeyaml/error/Mark;Lorg/yaml/snakeyaml/DumperOptions$ScalarStyle;)V
at com.fasterxml.jackson.dataformat.yaml.YAMLGenerator._scalarEvent(YAMLGenerator.java:908)
at com.fasterxml.jackson.dataformat.yaml.YAMLGenerator._writeScalar(YAMLGenerator.java:879)
at com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.writeNull(YAMLGenerator.java:787)
at com.fasterxml.jackson.databind.ser.std.NullSerializer.serialize(NullSerializer.java:30)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serializeNull(DefaultSerializerProvider.java:495)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:303)
at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1514)
at com.fasterxml.jackson.databind.ObjectWriter._writeValueAndClose(ObjectWriter.java:1215)
at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString(ObjectWriter.java:1085)
at io.swagger.v3.core.util.Yaml.pretty(Yaml.java:23)
at io.swagger.v3.parser.converter.SwaggerConverter.readResult(SwaggerConverter.java:113)
at io.swagger.v3.parser.converter.SwaggerConverter.readLocation(SwaggerConverter.java:91)
at io.swagger.parser.OpenAPIParser.readLocation(OpenAPIParser.java:16)
Debugging
After further debugging the stacktrace, my guess is that the jackson-dataformat-yaml artifact being used is somehow not 2.12.1 but 2.9 or less because in 2.9 the constructor of org.yaml.snakeyaml.events.ScalarEvent.<init> with that signature is not found (I could be wrong as well).
I have tried printing the
classpath
the testRuntime configuration and it's resolved artifacts.
and I see that the 2.12.1 version itself for jackson-dataformat-yaml is being picked up everywhere. But still I am not clear why the build (with junit) fails as explained above.
Could anyone help in debugging this further or any insight into why the test sourceSet for JUnits is not resolving the artifacts correctly.
Appreciate all inputs.
Thanks.
I had an existing project without Gradle and needed to add com.google.code.gson:gson:+ library to work with JSON objects. To begin with I ran either gradle init or gradle build, I'm not sure. This caused my java classes with a main() not to run as the source path was wrong/changed. I have changed the structure following advice to at least get the classes to compile and run, but I still have this warning in run configurations "Warning: Class 'Main' not found in module 'src'" ;
If I set Use classpath of module to src.main, the warning goes away but when I run Main.main() Gradle seems to execute Gradle tasks, like this - this will run indefinitely;
Here is my project structure;
This is my build.gradle file;
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java project to get you started.
* For more details take a look at the Java Quickstart chapter in the Gradle
* User Manual available at https://docs.gradle.org/6.3/userguide/tutorial_java_projects.html
*/
plugins {
// Apply the java plugin to add support for Java
id 'java'
// Apply the application plugin to add support for building a CLI application.
id 'application'
// idea plugin? // I added this to original build.gradle file
id 'idea'
}
repositories {
// Use jcenter for resolving dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
mavenCentral()
google()
}
dependencies {
// This dependency is used by the application.
implementation 'com.google.guava:guava:28.2-jre'
// Use JUnit test framework
testImplementation 'junit:junit:4.12'
// For use with JSONUtil class // I added this to original build.gradle file
compile 'com.google.code.gson:gson:+'
}
application {
// Define the main class for the application.
mainClassName = 'java.Main' // changed to 'Main' and I can `gradle run` seems to actually run Main.java
}
I have imported com.google.gson.JsonObject and com.google.gson.JsonParser from com.google.gson:gson:2.8.6 library, with no code inspection warnings, i.e available at compile time. If I run my code with a JsonObject jsonObject = new JsonObject I get the error;
Exception in thread "main" java.lang.NoClassDefFoundError: com/google/gson/JsonParser
at HttpUtils.getAccessToken(HttpUtils.java:80)
at Main.auth(Main.java:75)
at Main.play(Main.java:36)
at Main.main(Main.java:17)
Caused by: java.lang.ClassNotFoundException: com.google.gson.JsonParser
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 4 more
Line 80 of HttpUtils.java;
JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject(); // todo: status 200 "success" else failed
accessToken = jsonResponse.get("access_token").getAsString();
System.out.println(accessToken);
I understand this means that JVM can't compile a .class for JsonParser? I suppose this means the compiler has no knowledge of the library existing, which makes me suspect that Gradle isn't configured properly with the project, as it has downloaded the library, but not added a path to it?
I have tried gradle cleanIdea and then gradle idea. I have rebuilt the the project. I have "Mark directory as source root" on various directories for testing being careful to revert when it failed to change behaviour.
Edit;
I have added a package com.example in the src.main.Java directory and added the java files.
I edited run configuration for Main.java to
Main class: com.example.Main
Use classpath of module: src.main
I also changed the build.gradle file to;
application {
// Define the main class for the application.
mainClassName = 'com.example.Main'
}
Main runs but I am stuck at this point, which seems to run indefinitely;
Also, I am sure I right clicked on build.gradle and selected import, although I can't recreate this as the option isn't available now.
Edit 2;
I have been able to get the classes Main and Test with main() to run by putting them in the test/java/src package, and using unusual run configuration with warnings. Although on closer inspection, it seems to be running code that is previously compiled somewhere, as any changes I make aren't reflected in output.
Here is my project structure at the moment;
This is my run configuration that actually runs main in the standard output console, rather than a Gradle Task. It's clearly wrong, as Main is not in the com.example package or src.main module. If I set it correctly using module src.test and main class src.Main Gradle runs as screenshot 5.
Edit 3;
I see now that Gradle has took over responsibility to build and run the java files. I didn't know running in the output could be done with another CLI app and I admit it confused me, so please forgive anything above that seems stupid, I'm learning and figuring this out as I go.
I found in InteliJ settings Build, Execution, Deployment > Build Tools > Gradle I can change the Build and run using option between InteliJ IDEA and Gradle. The only issue I'm having with Gradle now I understand what is happening is Gradle doesn't seem to update my .class files when I run my main() with Gradle. Maybe this is for another question though.
mainClassName = 'java.Main' // changed to 'Main' and I can "gradle run" seems to actually run Main.java
This is not correct. Based on screenshot - you have not package named java (also I doubld that this is a valid name for a Java package). Create proper package inside src/main/java directory and specify it in the Main source file and in build.gradle file.
Also make sure you have imported build.gradle file in IDE, see Link a Gradle project to an IntelliJ IDEA project
I'm using gradle to build my android project and am not able to run single local unit test. I have several test classes and one of them is MockServerTest and I only want to run test methods in this class.
I tried using gradle -Dtest.single=MockServerTest test but it turned out running all my tests, including these in other test classes.
I also tried gradle test --tests MockServerTest but an error occurred said
Test filtering is not supported for given version of junit. Please upgrade junit version to at least 4.6.
But I'm using junit 4.12 in my gradle file
testCompile 'junit:junit:4.12'
I'm using gradle 2.4 with com.android.tools.build:gradle:1.2.3.
Also, how can I run a single test method inside a single test class?
BTW, I'm able to run single test method inside Android Studio, by right clicking on the test method and select run targetTestMethod() from the menu. But how can I achieve this in the terminal? I guess Android Studio also trigger a certain command to do this. How can I see what that command is?
Figured it out myself. I have to run
gradle testDebug --tests com.my.package.TestClassName
There are two things to note here.
1. You have to use gradle testDebug or gradle testRelease instead of just gradle test. If you have build variant, you have to use gradle testVariantNameDebug or gradle testVariantNameRelease
2. You have to specify the whole qualified class name, means including the package name.
You can use Android Gradle plugin DSL to set up test tasks filters like this:
android {
testOptions {
unitTests.all {
it.testNameIncludePattern = "*.SomeTest"
}
}
}
You can find more information on testOptions here and filters here.
Have you tried running gradle test -Dtest.single=MockServerTest? More information can be found here.
Follow up question to this question.
How do I store method parameter names for classes when building with Gradle (build.gradle file)?
According to Java tutorials:
To store formal parameter names in a particular .class file, and thus
enable the Reflection API to retrieve formal parameter names, compile
the source file with the -parameters option to the javac compiler.
So How do I pass the "-parameters" to the javac compiler using Gradle?
I tried the suggested solution here, by adding the below into my build.gradle file with no luck.
apply plugin: 'java'
compileJava {
options.compilerArgs << '-parameters'
options.fork = true
options.forkOptions.executable = 'javac'
}
I'm using eclipse and if I enable this (in Window -> Preferences -> Java -> Compiler), it works fine.
Store information about method parameters (usable via reflection)
But I would rather have this setting set by my build system, so i don't depend on eclipse and so others can use my buildt .jar files.
I use:
Eclipse 4.4.2
Gradle IDE 3.6.4 (eclipse plugin)
To get gradle itself to compile with -parameters add the following to your build.gradle:
compileJava.options.compilerArgs.add '-parameters'
compileTestJava.options.compilerArgs.add '-parameters'
In order to use Gradle to generate Eclipse project files where -parameters is set for javac: Use a tip from this gradle forum post and add the following to your build.gradle:
eclipseProject {
doLast {
// https://discuss.gradle.org/t/how-to-write-properties-to-3rd-party-eclipse-settings-files/6499/2
def props = new Properties()
file(".settings/org.eclipse.jdt.core.prefs").withInputStream {
stream -> props.load(stream)
}
props.setProperty("org.eclipse.jdt.core.compiler.codegen.methodParameters", "generate")
file(".settings/org.eclipse.jdt.core.prefs").withOutputStream {
stream -> props.store(stream, null)
}
}
}
(Apparently a) the Gradle Eclipse plugin doesn't know how to translate the compiler option -parameters to the .settings/org.eclipse.jdt.core.prefs setting org.eclipse.jdt.core.compiler.codegen.methodParameters=generate and b) there's no standard Gradle task that manipulates any of the property files in .settings, so you've got to roll your own.)
This is for Gradle 2.8.
sourceCompatibility=1.8
[compileJava, compileTestJava]*.options*.compilerArgs = ['-parameters']
After some research for the same problem, one solution is to make something like this: https://github.com/codeborne/mobileid/blob/master/build.gradle
Add this to your build.gradle:
[compileJava, compileTestJava]*.options.collect {options ->
options.compilerArgs.add '-parameters'
}
It works for me with gradle 2.4
The Groovy plugin for Gradle claims that it "supports joint compilation, which allows to freely mix and match Groovy and Java code, with dependencies in both directions".
However, I don't think this applies to test code.
I have a Java 'sample' test in src/test/java... which uses a class which is located in src/test/groovy.
When trying to build with Gradle, I get an error like this:
SwingJavaFXSampleAppTestInJava.java:23: error: cannot find symbol
SwingJavaFXSampleAppTest swingJavaFx = new SwingJavaFXSampleAppTest();
Notice that SwingJavaFXSampleAppTest is a Groovy class that has not been compiled yet (in the Gradle output I can see that it did not run the compileTestGroovy before it tried compileTestJava because the former depends on the latter).
I am able to build this same project with Maven using the groovy-eclipse plugin.
Why does it not work in Gradle when it claims to support compilation in any order, and how can I make it work?
As explained in the Gradle User Guide, only code passed to GroovyCompile tasks is joint-compiled. So either you put both Java and Groovy code into src/main/groovy, or you reconfigure the source sets:
sourceSets.main.java.srcDirs = []
sourceSets.main.groovy.srcDirs = ["src/main/java", "src/main/groovy"]
For tests, replace all occurrences of main with test.
You should be able to move your java tests into src/test/groovy.