Groovy enhancements not being loaded (date, collections, numbers, etc) - groovy

I have a Groovy project built using Gradle. The issue happens when I build a jar that has all the dependencies (fatJar), so I'm forced to do everyting in the Java way and get none of the Groovy enhancements
When I try to use any of the Groovy enhancements, I get MissingMethodException, this happens on: (just to give some examples)
new Date().format("yyyyMMddhhmmss")
[1,2,3].average()
Dependencies are:
dependencies {
// Use the latest Groovy version for building this library
implementation 'org.codehaus.groovy:groovy-all:2.5.13'
implementation 'org.codehaus.groovy:groovy-dateutil:2.5.13'
//implementation 'org.codehaus.groovy:groovy-datetime:2.5.13'
// Use the awesome Spock testing and specification framework
testImplementation 'org.spockframework:spock-core:1.3-groovy-2.5'
compile 'log4j:log4j:1.2.17'
// TODO
//implementation 'com.github.ppazos:openEHR-OPT:Tag'
compile fileTree(dir: 'lib', include: '*.jar')
}
This is the project https://github.com/ppazos/testehr
Not really sure what is going on.

Related

Running an instrumented test in Android Studio without simulating user actions

I have written some code that manipulates MotionEvent instances, and want to write a unit test for it.
The unit test needs to validate my manipulations only; it does not need to simulate any user actions.
I understand it needs to be an instrumented test to be able to use the methods of MotionEvent; I need the actual methods, not any mocking.
I have defined an instrumented test in the directory src/androidTest/...; however, it still throws the exception
java.lang.RuntimeException: Method obtain in android.view.MotionEvent not mocked.
My build.gradle file for the module has the following entries:
defaultConfig {
...
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
...
dependencies {
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
The imports in my test class are as follows:
import android.view.MotionEvent;
import org.junit.Test;
import static org.junit.Assert.*;
How can I run this test?
My mistake was as follows.
I initially thought that a local unit test would suffice, since no user action was involved.
It turned out to be wrong: the local unit tests do not get access to the Android methods.
I moved my file containing the test, to the place prescribed for the instrumented tests, /src/androidTest/java/, but did not change the file; this can be seen in my imports.
For this reason it still ran as a local non-instrumented test.
After I realized it, I changed the file to mimic the ExampleInstrumentedTest created by Android studio together with my project. I also deleted the run configuration which was still a local test.
After that Android studio prompted me to create a new run configuration, and the test ran successfully.

Android Studio - Duplicate classes ... found in modules ... and

I've been looking around for hours, yet I can't find any explanation that fits with my situation.
Every time I build my project, I get this same error:
Duplicate class com.google.common.util.concurrent.ListenableFuture found in modules jetified-guava-20.0 (com.google.guava:guava:20.0) and jetified-listenablefuture-1.0 (com.google.guava:listenablefuture:1.0)
Go to the documentation to learn how to Fix dependency resolution errors.
Yet I have absolutely no idea which dependencies are causing this.
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
def dynamicanimation_version = '1.0.0'
implementation "androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version"
implementation 'com.plattysoft.leonids:LeonidsLib:1.3.2'
implementation 'com.ajts.androidmads.sqliteimpex:library:1.0.0'
implementation 'com.google.android.gms:play-services-ads:19.7.0'
implementation 'com.google.android.gms:play-services-auth:19.0.0'
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
implementation 'com.google.http-client:google-http-client-gson:1.26.0'
implementation('com.google.apis:google-api-services-drive:v3-rev136-1.25.0')
{
exclude group: 'org.apache.httpcomponents'
}
}
I can see them both when searching all classes:
yet I still have no clue where the issue is coming from.
I'm relatively new to this so I may have missed some information. I can provide any other code or error information you may need.
Any input is appreciated, thanks!
I have found the answer to this myself.
It turns out it has to do with certain firebase implementations.
Google has created a package to counter this
To solve this conflict, simply add this to your app-level build.gradle;
implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'

Choosing different libraries for compilation and runtime

I have two libraries with same classes defined in each one. However they have some different contents (methods/constants).
For example:
Library 1:
package com.test.package;
Class A {
// only method signatures
public void methodA() {
}
public void methodB() {
}
}
Library 2:
package com.test.package;
Class A {
public void methodA() {
// some logic that MUST be executed to provide backward compatibility
}
}
My application uses Library 1 and Library 2 and run in devices which have com.test.package.ClassA, but com.test.package.ClassA.methodB() will only exist in newer releases in framework. Said that, I need the Library 1 to be used to compile my application and the Library 2 to execute a different implementation of methodA().
I have tried to do this in Android Studio using .jar and .aar libraries format, but none of them worked for me.
Is it possible to set this configuration in an Android Studio project?
I am building both Library 1 and 2, and I cannot add methodB() in Library 2.
For a simple Java application, you can do this by unlinking the compile and runtime configurations. I set up an example repository here.
The idea is shown in this commit, but can be described as manually resetting the runtime configuration so that it doesn't include the contents of the compile configuration. After doing so, you can just include your runtime library variation in the runtime configuration.
The application's build.gradle becomes something like:
apply plugin: 'application'
mainClassName = 'my.package.MyAppClass'
configurations.runtime.extendsFrom = [] // Reset runtime configuration
dependencies {
compile 'my.group:my.artifact:2.0' // Library 1, with the new method
runtime 'my.group:my.artifact:1.0' // Library 2, without the method
}
For Android, this can be a little more complicated. The problem is that there's no runtime configuration for Android (because you don't execute it on your computer, unless you're using Robolectric or something similar).
I think there are a few workarounds you can probably use, but one initial suggestion would be to create a wrapper library that abstracts away the dependency on the other libraries. This wrapper library you can compile with the newest library version (Library 1, with the new method). You could then include the wrapper library in the Android app while setting it as a non-transitive dependency and including the other library version:
dependencies {
compile 'my.group:my.wrapped.artifact:0.1' {
transitive = false // Don't include dependencies of the wrapper
// i.e., don't include version 2.0 of the lib.
}
compile 'my.group:my.artifact:1.0'
}
This should work because by setting the dependency as non-transitive Gradle doesn't recursively include the dependencies of the wrapper library, so the version used to compile the wrapper isn't included (in theory) in the APK. You can therefore add the old version without causing a conflict.
An example is set up in the same repository, under the Android branch. Firstly, two Java libraries are created. Then an Android library is created to wrap around the compile-time library. An example activity is created to show how using the wrapper library uses the compile-time library. Then, the latest commit shows how the app is configured to use the wrapper library (which compiles with the newest library) but forces the old library to be included instead in the runtime.
Hope this helps =)

Is it possible to use classes compiled by Gradle buildSrc in main Groovy project?

Classes compiled by buildSrc/build.gradle are not resolved at runtime when they are used in main PROJECT classes.
My Groovy project structure looks like this:
-PROJECT
-buildSrc/
-build.gradle
-/src/main/groovy
- com.company.global.test.report
-src/test/groovy
-build.gradle
Is there something I can add to the top-level PROJECT/build.gradle to allow the classes compiled by it to use the classes compiled by buildSrc/build.gradle?
buildSrc is its own build (not project) that gets executed before the main build. Its sole purpose is to make some classes (plugins, tasks, regular classes) available to the build scripts of the main build. Hence you could call it a "meta-build".
Technically, it would be possible to add the compiled classes of buildSrc to the compile or runtime class path of a project in the main build, but I don't recommend to do it. There is very likely a better way to achieve your goals (but I don't know what those are).
Here is how to do it with Gradle 2.12:
In your_project/buildSrc/build.gradle
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
// Thanks to this, IDE like IntelliJ will provide you with "Navigate to sources"
artifacts {
archives sourcesJar
}
In your_project/build.gradle
ext.buildSrcJars = fileTree("$rootDir/buildSrc/build/libs") { include("*.jar") exclude("*sources.jar")}
// Works in every subproject
dependencies {
compile buildSrcJars
}

Not able to use variables defined in classes within groovy annotations

I am trying to port some code from the Dropwizard examples from java to groovy.
I see that within java, I can use the following code without any issues:
package com.example.helloworld;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
#Produces(MediaType.APPLICATION_JSON)
public class HelloWorldService{
}
However, with the groovy compiler ( both 1.8 and 2.0.6 ), the class fails to compile with a noClassFoundException around MediaType.APPLICATION_JSON
If I change this code to use the actual string value
#Produces('application/json')
public class HelloWorldService{
}
everything works perfectly.
Are there any differences between the way groovy resolves annotations and the way that java does?
For completeness, this is part of a gradle project and here is my build.gradle ( the file goes under src/groovy/com/example/helloworld )
apply plugin: 'groovy'
// Set our project variables
project.ext {
dropwizardVersion = '0.6.1'
}
repositories {
mavenCentral()
}
dependencies {
compile group: 'com.yammer.dropwizard', name: 'dropwizard-core', version: dropwizardVersion
groovy group: 'org.codehaus.groovy', name: 'groovy-all', version: '1.8.7'
}
The compilation error is:
Caused by: java.lang.RuntimeException:
java.lang.ClassNotFoundException:
com.sun.ws.rs.ext.RuntimeDelegateImpl ... 17 more Caused by:
java.lang.ClassNotFoundException:
com.sun.ws.rs.ext.RuntimeDelegateImpl at
org.gradle.api.internal.tasks.compile.TransformingClassLoader.findClass(TransformingClassLoader.java:47)
The problem is caused by an unfortunate limitation of the Groovy compiler, namely that it uses reflection to access classes on the compile class path. This may in turn trigger other classes to get loaded, which may not be available on the compile class path. Typically (but not always) these are runtime dependencies.
In the concrete case, the Groovy compiler loads javax.ws.rs.core.MediaType via reflection, which ultimately results in com.sun.ws.rs.ext.RuntimeDelegateImpl being loaded via Class.forName (triggered by a static initializer), which isn't on the compile class path. The solution is to put that class on the compile class path. (In the longer run, the solution is to fix the standalone Groovy compiler not to use reflection, and from what I know this is already in the queue.) If your module's transitive dependencies aren't an issue, the simplest way to achieve this is:
dependencies {
compile "com.sun.jersey:jersey-client:1.15"
}
I suspect that the Eclipse Groovy compiler doesn't have this problem because it doesn't use reflection to access the compile class path. I'd expect GMaven to blow up like Gradle, unless it is configured to use the Eclipse compiler (which isn't currently supported by Gradle).

Resources