I'm new to gradle, trying to set up an old project (which used ant). Project setup is fine, though rather complex because of some ugly requirements where different resources need to go multiple different places, with some needing to be filtered according to different properties files etc..
Anyway, I am now trying to set up testing. The problem is that the tests require a hibernate.properties file that is different to the one used in the main project. So, I added a reference to the relevant resource folder:
sourceSets {
test {
resources {
srcDirs "${outputDir}/test/generated-src"
}
}
}
The hibernate.properties file for the main project is in:
sourceSets {
main {
resources {
srcDirs "${outputDir}/generated-src"
}
}
}
(The reason they are not just in src/main/resources etc, is that they required some special handling before they can be used.)
Using "gradle test" works (probably by luck), because it uses the hibernate.properties from the test folder.
But, running junit tests from Eclipse does not work, because in Eclipse the "${outputDir}/test/generated-src" folder gets added to the classpath AFTER the main one. So the tests find the main hibernate.properties, and fail...
I tried to mess around with reordering the classpath for Eclipse, but failed. A workaround is to manually change the order in Eclipse->project properties->Build path->Order and export, but I would like a proper solution.
I'm thinking this probably isn't an unknown problem, and there is probably a proper gradle solution to it?
Related
I have two versions of the same Java class (same name / methods). Since it's Java, both .java files have the same name. I want to configure gradle in such a way that I can build a "debug" version of my application that pulls in one of these files, and a "production" version of my application that pulls in the other one. How would I go about doing this?
This class has only static methods. I don't ever want to make an instance of this class. I additionally don't want to add the overhead of an if statement in each of the methods on this class to check which version I'm in.
Following #JFabianMeier's answer you could use 4 projects:
with the production version class
with the debug version class
with code that uses either of the two, parameterized according to Migrating Maven profiles ... → Example 6. Mimicking the behavior of Maven profiles in Gradle. (I'm also a Maven guy and therefore can't tell you exactly how to do it in Gradle.)
a multi-project with 1./2./3. as sub[-]projects for building all of them in one go, maybe parameterized to build just 1.+ 3. or 2.+ 3.
Have you tried creating production and debug source directories/sets? According to the docs you can use multiple directories when specifying source directories in your source set. Try dropping the different versions of your class in their respective production/debug source directories.
I haven't tested myself (not sure about the syntax), but this is based on the Gradle's Java compilation documentation.
sourceSets {
// Could also name this production
main {
java {
srcDirs ['src/main/java', 'src/prod/java']
}
}
debug {
java {
srcDirs ['src/main/java', 'src/debug/java']
}
}
}
You could do the following:
Put the class into a separate project (so generate a separate jar from it)
Then you can have two different jars, for production and debugging
Then you can pull either one or the other jar in gradle depending on a parameter.
Alternatively, you could look into template engines like Velocity which allow you to generate source code during the build depending on variables and then compile it.
Android has a neat feature called Product Flavors. It lets you swap classes at compile time effortlessly and keep your project clean.
This post is very good to get a taste of it: https://android-developers.googleblog.com/2015/12/leveraging-product-flavors-in-android.html
And here is the full documentation: https://developer.android.com/studio/build/build-variants#product-flavors
I know there are a lot of questions that seem similar. I have also spent a few hours getting to grips with Gradle multiprojects. But I still don't understand what the best course of action is here. Incidentally I am using Groovy as my coding language, but explanations referencing Java would be just as good.
I have developed an Eclipse Gradle project, "ProjectA", which in particular has a class, IndexManager, which is responsible for creating and opening and querying Lucene indices.
Now I am developing a new Eclipse Gradle project, "ProjectB", which would like to use the IndexManager class from ProjectA.
This doesn't really mean that I would like both projects to be part of a multiproject. I don't want to compile the latest version of ProjectA each time I compile ProjectB - instead I would like ProjectB to be dependent on a specific version of ProjectA's IndexManager. With the option of upgrading to a new version at some future point. I.e. much as with the sorts of dependencies you get from Maven or JCenter...
Both projects have the application plugin, so ProjectA produces an executable .jar file whose name incorporates the version. But currently this contains only the .class files, the resource files, and a file called MANIFEST.MF containing the line "Manifest-Version: 1.0". Obviously it doesn't contain any of the dependencies (e.g. Lucene jar files) needed by the .class files.
The application plugin also lets you produce a runnable distribution: this consists of an executable file (2 in fact, one for *nix/Cygwin, one for Windows), but also all the .jar dependencies needed to run it.
Could someone explain how I might accomplish the task of packaging up this class, IndexManager (or alternatively all the classes in ProjectA possibly), and then including it in my dependencies clause of ProjectB's build.gradle... and then using it in a given file (Groovy or Java) of ProjectB?
Or point to some tutorial about the best course of action?
One possible answer to this which I seem to have found, but find a bit unsatisfactory, appears to be to take the class which is to be used by multiple projects, here IndexManager, and put it in a Gradle project which is specifically designed to be a Groovy library. To this end, you can kick it off by creating the project directory and then:
$ gradle init --type groovy-library
... possible to do from the Cygwin prompt, but not from within Eclipse as far as I know. So you then have to import it into Eclipse. build.gradle in this library project then has to include the dependencies needed by IndexManager, in this case:
compile 'org.apache.lucene:lucene-analyzers-common:6.+'
compile 'org.apache.lucene:lucene-queryparser:6.+'
compile 'org.apache.lucene:lucene-highlighter:6.+'
compile 'commons-io:commons-io:2.6'
compile 'org.apache.poi:poi-ooxml:4.0.0'
compile 'ch.qos.logback:logback-classic:1.2.1'
After this, I ran gradle jar to create the .jar which contains this IndexManager class, initially without any fancy stuff in the manifest (e.g. name, version). And I put this .jar file in a dedicated local directory.
Then I created another Gradle project to use this .jar file, the critical dependency here being
compile files('D:/My Documents/software projects/misc/localJars/XGradleLibExp.jar' )
The file to use this class looks like this:
package core
import XGradleLibExp.IndexManager
class Test {
public static void main( args ) {
println "hello xxx"
Printer printer = new Printer()
IndexManager im = new IndexManager( printer )
def result = im.makeIndexFromDbaseTable()
println "call result $result"
}
}
class Printer {
def outPS = new PrintStream(System.out, true, 'UTF-8' )
}
... I had designed IndexManager to use an auxiliary class, which had a property outPS. Groovy duck-typing means you just have to supply anything with such a property and hopefully things work.
The above arrangement didn't run: although you can do build and installdist without errors, the attempt to execute the distributed executable fails because the above 6 compile dependency lines are not present in build.gradle of the "consumer" project. When you put them in this "consumer" Gradle project's build.gradle, it works.
No doubt you can add the version to the generated .jar file, and thus keep older versions for use with "consumer" projects. What I don't understand is how you might harness the mechanism which makes the downloading and use of the dependencies needed by the .jar as automatic as we are used to for things obtained from "real repositories".
PS in the course of my struggles today I seem to have found that Gradle's "maven-publish" plugin is not compatible with Gradle 5.+ (which I'm using). This may or may not be relevant: some people have talked of using a "local Maven repository". I have no idea whether this is the answer to my problem... Await input from an über-Gradle-geek... :)
You should be able to update the Eclipse model to reflect this project-to-project dependency. It looks something like this (in ProjectB's build.gradle):
apply plugin: 'eclipse'
eclipse {
classpath.file.whenMerged {
entries << new org.gradle.plugins.ide.eclipse.model.ProjectDependency('/ProjectA')
}
project.file.whenMerged {
// add a project reference, which should show up in /ProjectB/.project's <projects> element
}
}
These changes may be to the running data model, so they may not actually alter the .classpath and .project files. More info can be found here: https://docs.gradle.org/current/dsl/org.gradle.plugins.ide.eclipse.model.EclipseModel.html
This issue is discussed here: http://gradle.1045684.n5.nabble.com/Gradle-s-Eclipse-DSL-and-resolving-dependencies-to-workspace-projects-td4856525.html and a bug was opened but never resolved here: https://issues.gradle.org/browse/GRADLE-1014
There are a ton questions regarding getResource or getResourceAsStream returning null and so far I understand the issue but I currently cannot properly solve it.
I have a resource file which is used by some class in production. The file is located in
app\src\main\res\raw\some.def
The class SomeManager uses this to access this file:
InputStream stream = SomeClass.class.getResourceAsStream("/res/raw/some.def");
This succeeds when running the debug variant of the application on the emulator and it also succeeds when running the debug variant of the instrumented tests. I assume because the resource is properly packaged into the jar?
However when I run some local jUnit tests in android studio this resource is not found. I did not fully understand what is exactly executed when running a local test and I am not sure how to provide the resource file in a way that can be loaded in a test.
I would like to avoid doubling this resource file because it is actually something I want to test, I also would like to not change the getResourceAsStream path because this is the production file I want to test.
I am using gradle and android studio if that matters.
I debugged this issue with Sysinternal's Process Monitor and realized that when I run code locally on my machine the resources are as streams are looked up from various different locations on disk. One of those locations is
<build_directory>/intermediate/classes/<build_type> where it is obviously missing.
The solution to this was to create a copy task that performs the copying and make it robust enough to work for all build types.
So I modified my app's gradle file and added those dynamic tasks:
android.buildTypes.all{ theBuildType ->
task "copyDebugAssets_${theBuildType.name}"(type: Copy){
from "${projectDir}/src/main/res"
into "${buildDir}/intermediates/classes/${theBuildType.name}/res"
eachFile { println it.name }
}
}
tasks.whenTaskAdded { task ->
// println "A message which is logged at QUIET level ${task.name}"
if (task.name.startsWith("process") && task.name.endsWith("Resources")) {
def partInBetween = task.name.substring("process".length(), task.name.indexOf("Resources")).toLowerCase()
if (partInBetween == "debugandroidtest") {
return
}
def dependentTask = "copyDebugAssets_${partInBetween}"
println "Registering ${dependentTask} to ${task.name} for config '${partInBetween}'"
task.dependsOn dependentTask
}
}
I have really no idea on how to properly use gradle but the first statement generates as many copyDebugAssets_xxx tasks as there are build types. After syncing you can see and execute the in the gradle projects.
To avoid calling them whenever a clean or rebuild is done manually, the second part registers the copyDebugAssets_xxx copy tasks to the various process<Configuration>Resources tasks, which are then called automatically. So far I can run local unit tests in multiple build type successfully.
I have an issue with some gradle task that should run tests. Since this is some legacy from ant tasks we do not want to include them into our test suite. Especially considering that those ant ones are in testng, and those made by us, and used on regular basis are made using spock and junit.
The problem is that those tests are using some context which works pretty well when I run those tests under eclipse IDE, but it fails if I try to do sth like:
task testNgTesting(type: Test, dependsOn: testClasses){
useTestNG()
includes = ["**/*IT*"]
}
But when I try to use that task I get errors like "org.hibernate.MappingException: Unknown entity:" or "java.lang.IllegalArgumentException: No query defined for that name"
Actually the problem is deeper. Gradle is trying to be smart and from whatever folder it has defined it puts classes files into classes folder, and all the other files into resources. When persistence.xml is loaded it scans for annotated entities starting with classpath root for folder it is present in (i.e. build/resources/main). Since all those classes are in build/classes/main it fails to find them. The workaround I've made is introduce two copy tasks. one named is copying persistence.xml into classes folder, and another is moving this file back to resources after the tests are finished. You might want to use something like
testNgTesting.finalizedBy(cleanAfterIntegrationTests) to make sure the cleanup occurs even if there are some tests that fails.
See the following Maven generated project
target
classes
test-classes
src
main
java
scripts
resources
datasource-settings.xml
test
java
resources
datasource-settings.xml
I would like, when running a test, to use the settings found in test/resources/datasource-settings.xml instead of main/resources/datasource-settings.xml. Is it possible ? If so, what should i do to get my goal ?
Resources placed in ${basedir}/src/test/resources (the default location) will be automatically added to the class path set up by Maven for your unit tests and take precedence over resources placed in ${basedir}/src/main/resources. So what you want to do is actually just the default behavior.
If you haven't modified the resource settings in your POM, the test resources should show up in your classpath first, so a test should find that file before the main one without you needing to do anything extra. What sort of behavior are you seeing?