Migrating Eclipse Android Junit Tests into Android Studio Gradle - eclipse

We are trying to migrate our Eclipse projects using ant builds into Android Studio using gradle. So far all is good except for our JUnit tests that use external json files. We have a ton of these where the the external file is located in the same directory as the java file. Is there a way to keep the java code and the json file in the same location and just modify the build scripts in gradle?
Current build directory is something like this \com\pack\krf\ contains MyFileTest.java and data.json. Source code to load json is this:
getClass().getResourceAsStream("data.json");
I do not want to change 300+ java files that have this same structure. Plus I do not want to group into the resource directory in gradle since some of these files will have the same name.

Here's the solution one of my teammates came up with. Add this to your build.gradle file after the android declaration. The print path is for debugging.
task alterResourcePath << {
sourceSets.testDebug.resources.srcDir('src/test/java')
sourceSets.testDebug.resources.srcDirs.each {
File f->
if(f.exists()){
println f.path
}
}
}
test.dependsOn alterResourcePath

By default gradle (like Maven) puts the resources under src/main/resources, so you'll have to tell Gradle to look for them in src/<something>/java instead:
android {
sourceSets {
instrumentTest {
resources {
srcDirs = ['src/instrumentTest/java']
}
}
}
}
if you are running robolectric test you do the same, but the robolectric plugins out there uses standard java source sets. So you won't do this inside the Android extension:
sourceSets {
test {
resources {
srcDirs = ['src/test/java']
}
}
}
If you use other sourceSets (per flavor or per build Type) you'll need to update those as well.

Related

Gradle DSL - Eclipse Equivalent for IDEA Module Property

Good localtime,
I am in the process of updating legacy (4.8.1) Gradle build files for a big-McLarge-huge, multimodule project. We utilize an intellij.gradle file which has the following line (marked by comment):
idea {
module {
inheritOutputDirs = true // <-- HOW DO I DO THIS
downloadJavadoc = true
downloadSources = true
}
workspace.iws.withXml { provider ->
def node = provider.asNode()
def dynamicClasspath = node.component.find { it."#name" == "dynamic.classpath" }
if (dynamicClasspath != null) {
dynamicClasspath."#value" = "true"
}
}
From the 4.8.1 DSL docs:
If true, output directories for this module will be located below the
output directory for the project; otherwise, they will be set to the
directories specified by IdeaModule.getOutputDir() and
IdeaModule.getTestOutputDir().
Any ideas on what the Eclipse DSL equivalent of inheritOutputDirs? Should this be handled using the eclipseClasspath API? Right now everything is building fine, but the Eclipse Java builder is is flagging things.
References:
https://docs.gradle.org/4.8.1/dsl/org.gradle.plugins.ide.idea.model.IdeaModule.html
https://docs.gradle.org/4.8.1/dsl/org.gradle.plugins.ide.eclipse.model.EclipseClasspath.html
Usually this would have been picked up through sourceSets but I can't see what your project looks like...
If your subproject uses Gradle to generate sources into /build/cxf/generated-sources directory, then you can tell Eclipse via Gradle DSL to include that as a source folder like this:
plugins { id 'eclipse' }
eclipse.classpath.file.whenMerged {
// this is the brute-force approach; there is likely a better way to add a source folder
entries << new org.gradle.plugins.ide.eclipse.model.SourceFolder('build/cxf/generated-sources', null)
}
Once this is run (via gradle eclipseClasspath) you should see a build/cxf/generated-sources folder under your project node in the Package Explorer or Project Explorer. Sort of like this:
NOTE: This is untested because I don not have a sample project to work with.
There is more discussion here: How to add gradle generated source folder to Eclipse project?

How to configure multiplatform JFace project for Windows and Linux in Gradle?

I am writing a cross-platform application using JFace that should run on both Windows and Linux.
Unfortunately, JFace requires different SWT versions depending on platform — it requires org.eclipse.platform:org.eclipse.swt.gtk.linux.x86_64 on 64 bit Linux and org.eclipse.platform:org.eclipse.swt.win32.win32.x86_64 on 64 bit Windows.
I have come up with the following temporary solution:
import org.gradle.internal.os.OperatingSystem
plugins {
// ...
id("com.github.johnrengelman.shadow") version "6.0.0"
}
// ...
val swtVersion = "3.114.100"
val swtName = "org.eclipse.swt." +
(System.getProperty("platform") ?: OperatingSystem.current().let { current ->
when {
current.isLinux -> "gtk.linux"
current.isWindows -> "win32.win32"
current.isMacOsX -> "cocoa.macosx"
else -> throw RuntimeException("Unsupported operating system: $current")
}
} + if (System.getProperty("os.arch").contains("64")) ".x86_64" else ".x86")
configurations.all {
resolutionStrategy.eachDependency {
if (requested.name == "org.eclipse.swt.\${osgi.platform}") {
useTarget("${requested.group}:$swtName:${requested.version}")
}
}
}
dependencies {
// ...
implementation("org.eclipse.platform", "org.eclipse.jface", "3.20.0")
}
application {
mainClassName = "com.example.myapp.AppKt"
}
It allows to build JAR that runs only on host OS with:
gradle shadowJar
and to cross compile for Windows with:
gradle shadowJar -Dplatform=win32.win32.x86_64
When ran on a wrong platform it fails (as expected) with:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Could not load SWT library. Reasons:
no swt-win32-4934r6 in java.library.path: [/usr/java/packages/lib, /usr/lib64, /lib64, /lib, /usr/lib]
no swt-win32 in java.library.path: [/usr/java/packages/lib, /usr/lib64, /lib64, /lib, /usr/lib]
Can't load library: /home/nawordar/.swt/lib/linux/x86_64/libswt-win32-4934r6.so
Can't load library: /home/nawordar/.swt/lib/linux/x86_64/libswt-win32.so
at org.eclipse.swt.internal.Library.loadLibrary(Library.java:342)
at org.eclipse.swt.internal.Library.loadLibrary(Library.java:256)
at org.eclipse.swt.internal.C.<clinit>(C.java:19)
at org.eclipse.swt.widgets.Display.<clinit>(Display.java:145)
at com.example.myapp.AppKt.main(App.kt:9)
at com.example.myapp.AppKt.main(App.kt)
I am looking for either of two solutions:
Create tasks that build JARs with different names and dependencies for each platform and a meta-task that builds both JARs at once;
Create one JAR that runs on both platforms.
As for the first one, I am new to Gradle and I cannot find a way to create a task that produces JAR with name specific to the platform and has platform-specific dependencies. On this website the classifier property is mentioned, but it is deprecated. archiveClassifier, that is supposed to replace it, is read-only, so I don't know how I can use it. The second problem I have with this solution is that I cannot find how to declare task specific resolution strategy.
As for the second one, I'm not sure if that is possible, but if it is, it would be a preferable solution.

Running Vert.x (w/ES4X) via Eclipse

This question is a follow-up to:
Running Vuetify on Vert.x (w/ES4X)
I would like to be able to run ES4X via Eclipse (instead of NPM). I'm not exactly sure if it's possible or how to wire it in.
Let's say I have the following build.gradle.file
plugins {
id 'java'
id 'application'
id 'com.johnrengleman.shadow' version "5.0.0"
}
sourceCompatibility='1.8'
mainClassName='io.vertx.core.Launcher'
repositories {
mavenCentral()
}
dependencies {
implementation 'io.vertx:vertx-core:3.7.1'
implementation 'io.vertx:vertx-web:3.7.1'
implementation 'io.vertx:vertx-lang-js:3.7.1'
// implementation 'io.reactiverse:es4x:0.8.0'
// implementation 'io.reactiverse:es4x-pm:0.8.0'
}
processResources {
from '/src/main/js'
}
shadowJar {
classifier = 'fat'
manifest {
attributes 'Main-Verticle' : 'index.js'
}
mergeServiceFiles {
include 'META-INF/services/io.vertx.core.spi.VerticleFactory'
}
}
and my src/main/js/index.js looks like the one from the other referenced post:
import { Router, StaticHandler } from '#vertx/web';
const app = Router.router(vertx);
app.get().handler(StaticHandler.create("dist"));
vertx.createHttpServer().requestHandler(app).listen(8080);
If I create an executable jar via shadowJar, I get javax.script.ScriptExceptions due to Nashorn choking on the index.js contents (as expected).
If I uncomment the es4x implementation in the gradle build, I get ClassNotFound exceptions for org.graalvm.polyglot.io.FileSystem
So how would I correctly modify this app to take advantage of ES4X? I guess the equivalent of what the 'es4x init' would do?
Say that you have your es4x application and a package.json, when you execute:
npm install
You will get inside node_modules a few extra folders:
.bin
.lib
In the .bin directory there is a es4x-launcher.jar file you can use to start your application from Eclipse. It will refer to the dependencies which are unpacked to the .lib dir. In order to make things work fine the same JVM you have when running the npm install command should be used in eclipse. Otherwise you might end up missing dependencies. This is the case when running graalvm which will not require graaljs dependencies or when running on jdk8 which will not require jvmci dependencies.

Kotlin setup via gradle on eclipse

Struggling to get Kotlin running on eclipse.
I've started new graddle project. Added dependencies as prescribed on kotlin's site.
Build passes without errors.
I've created 'main.kt' file under src/java/main with:
fun main(args: Array<String>) {
println("foo")
}
BUT, I have two problems:
1. anything from kotlin e.g. println highlighted as 'unresolved reference'.
2. I can't run a program - Error: Could not find or load main class MainKt (rightclick on main.kr run as 'kotlin application')
If I create 'new kotlin project' everything works.
my graddle build script:
plugins {
id "org.jetbrains.kotlin.jvm" version "1.1.2-2"
}
repositories {
jcenter()
mavenCentral()
}
dependencies {
//api 'org.apache.commons:commons-math3:3.6.1'
implementation 'com.google.guava:guava:21.0'
testImplementation 'junit:junit:4.12'
compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.2-2"
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8"
compile "org.jetbrains.kotlin:kotlin-reflect"
testCompile "org.jetbrains.kotlin:kotlin-test"
testCompile "org.jetbrains.kotlin:kotlin-test-junit"
}
sourceSets {
main.java.srcDirs = ['src/main/java']
main.kotlin.srcDirs = ['src/main/java', 'src/main/kotlin']
main.resources.srcDirs = ['src/main/resources']
}
What did I do wrong?
I've zero Java knowledge if that helps, so probably I've made some trivial error.
UPDATE:
Installed a Spring plugin and generated a new web app via it including gradle.
But Kotlin behaves unpredictably there too.
At first I was not able to run it as run as Kotlin application and it errored with main could not be found, BUT sometimes it run and crashed immediately. It started to launch and crash after I've deleted and edited classes, tried creating it under other package, removing and adding Kotlin (I can't reproduce sequence to make it work again).
Fun part that gradle boot build launches everything and all works it somehow finds Kotlin's main.
Probably some issue with Kotlin plugin itself (it's load probably depends on certain events that doesn't always fire)
Add the following to your configuration:
apply plugin: 'eclipse'
eclipse {
classpath {
containers 'org.jetbrains.kotlin.core.KOTLIN_CONTAINER'
}
}
See https://gitlab.com/frnck/kotlin-gradle-eclipse for a working configuration.
I'd like to add to frnck answer that this is only part of the solution. I also had to add these lines:
eclipse.project {
buildCommand 'org.jetbrains.kotlin.ui.kotlinBuilder'
natures 'org.jetbrains.kotlin.core.kotlinNature'
natures 'org.eclipse.jdt.core.javanature'
linkedResource name: 'kotlin_bin', type: '2', locationUri: 'org.jetbrains.kotlin.core.filesystem:/aio/kotlin_bin'
}
For Eclipse 2018-12 and kotlin 1.3 the solution was a combination of other answers plus some additional settings file:
eclipse {
classpath {
//Adds the kotlin container to the classpath
containers 'org.jetbrains.kotlin.core.KOTLIN_CONTAINER'
//Fixes the right output path
defaultOutputDir = file('bin')
//Make all src folders output in the same output folder (default)
file {
whenMerged {
// use default Output for all source-folders. see also defaultOutputDir per project
entries.each { source ->
// only Source-folders in the project starting with '/' are project-references
if (source.kind == 'src' && !source.path.startsWith('/')) {
source.output = null
}
}
}
}
}
project{
buildCommand 'org.jetbrains.kotlin.ui.kotlinBuilder'
//Fixes the natures
natures 'org.jetbrains.kotlin.core.kotlinNature'
natures 'org.eclipse.jdt.core.javanature'
//Links the kotlin_bin folder (generated class files)
linkedResource name: 'kotlin_bin', type: '2', locationUri: "org.jetbrains.kotlin.core.filesystem:/${project.name}/kotlin_bin".toString()
file{
whenMerged{
def kotlinPrefs = file('.settings/org.jetbrains.kotlin.core.prefs')
def jdkHome = System.properties.'java.home'
if(!(jdkHome)){
throw new GradleException('No JDK home available for setting up Eclipse Kotlin plugin, setup env "java.home" or update this script.')
}
kotlinPrefs.write """\
codeStyle/codeStyleId=KOTLIN_OFFICIAL
codeStyle/globalsOverridden=true
compilerPlugins/jpa/active=true
compilerPlugins/no-arg/active=true
compilerPlugins/spring/active=true
eclipse.preferences.version=1
globalsOverridden=true
jdkHome=$jdkHome
""".stripIndent()
}
}
}
}
I would like to add to Felipe Nascimento's answer that the location of the .settings folder does not yet exist. It works when the line below is inserted into that answer.
def kotlinPrefs = file("../${project.name}/.settings/org.jetbrains.kotlin.core.prefs".toString())
I have found that the JAVA_HOME environment variable that is set when your run this task ;
gradle cleanEclipse eclipse
is the one that is included in the Eclipse BuildPath

Gradle Api Sources and Doc when writing Gradle Plugins

The question:
How do I get the sources and javadoc/groovydoc for the gradle-api code integrated into an Eclipse project?
Background:
I'm using Gradle to build a Gradle-plugin that I'm writing. I'm using Eclipse as an IDE for this project and my Gradle script for building this plugin is using the 'Eclipse' plugin to generate my Eclipse project. Also, I'm using Spring's Gradle plugin for Eclipse which grabs all my dependencies from my build.gradle file.
The dependencies block for this Gradle script has
dependencies {
compile localGroovy()
compile gradleApi()
// I want something like: 'compile gradleApiSources()' here
// I want something like: 'compile gradleApiDoc()' here as well
}
Justification:
As I'm learning to write Gradle plugins, it would be helpful to be able to see the documentation and even implementation for Gradle to help me learn what I'm doing.
This works for me in Eclipse:
plugins.withType(EclipsePlugin) {
plugins.withType(JavaBasePlugin) {
eclipse {
classpath {
file {
whenMerged { classpath ->
String gradleHome = gradle.getGradleHomeDir()
.absolutePath
.replace(File.separator, '/')
String gradleSourceDirectory = "${gradleHome}/src"
classpath.entries.each { entry ->
if (entry in org.gradle.plugins.ide.eclipse.model.AbstractLibrary
&& entry.library.path.contains('generated-gradle-jars')) {
entry.sourcePath =
new org.gradle.plugins.ide.eclipse.model.internal.FileReferenceFactory()
.fromPath(gradleSourceDirectory)
}
}
}
}
}
}
}
}
Make sure that your Gradle Home contains the source directory. If you use the wrapper this can be done by updating the distributionUrl to an -all version in the wrapper task.
You will also need to stop the Gradle daemons that are running otherwise they will keep their own "home": ./gradlew --stop, then you can go ahead and run the task: ./gradlew eclipse
See GRADLE-2133 (which this answer was adapted from)
I don't have an answer for eclipse but I can tell you how I do this for intellij which might give you some inspiration. It would be nice if this were available more easily.
private void addGradleSourceDeps() {
PathFactory pf = new PathFactory()
pf.addPathVariable('GRADLE_HOME', project.gradle.gradleHomeDir)
project.extensions.idea.module.iml.whenMerged { Module module ->
module.dependencies.grep {
it instanceof ModuleLibrary && ((ModuleLibrary) it).classes.grep { Path path ->
path.relPath.substring(path.relPath.lastIndexOf('/') + 1).startsWith('gradle-')
}
}.each { ModuleLibrary lib ->
// TODO this needs to be fixed for gradle 1.9 which now includes separate sub directory for each jar
// for now a workaround is to execute the following
// cd $GRADLE_HOME
// for each in $(find . -mindepth 2 -maxdepth 2 -type d ! -name META\-INF); do cp -a ${each} .;done
lib.sources.add(pf.path('file://$GRADLE_HOME$/src'))
}
module.dependencies.grep {
it instanceof ModuleLibrary && ((ModuleLibrary) it).classes.grep { Path path ->
path.relPath.substring(path.relPath.lastIndexOf('/') + 1).startsWith('groovy-all')
}
}.each { ModuleLibrary lib -> lib.sources.add(pf.path('file://$GROOVY_SRC_HOME$')) }
}
}
This relies on me having installed a gradle src distribution into a location available via the GRADLE_HOME path variable in intellij (and similar for GROOVY_SRC_HOME). You can also see my plugin currently uses gradle 1.8, the src layout changed in 1.9 so I need to fix this when I upgrade.