I'm trying to follow a tutorial about Android application. I'm using an dependency Fuel (which has a dependency to com.google.Gson deserializer). But Gson() is not imported by IDE.
I've tried to specify lower version of gson. I've re-synchronized all project gradle. I've tried to write import manually (import com.google.gson.Gson), but I can't use Gson() constructor. I've read manual about using Gson, but nothing seem to be changed. It's always the same way. Call constructor Gson() and after all static method... Gson().fromJson(....)
Here is section in my build.gradle (module:app)
// Fuel HTTP Client
implementation 'com.github.kittinunf.fuel:fuel:2.2.0'
implementation 'com.github.kittinunf.fuel:fuel-android:2.2.0'
implementation 'com.github.kittinunf.fuel:fuel-gson:2.2.0'
and In code, I'm using in ArticleDataProvider.kt:
class WikipediaDataDeserializer : ResponseDeserializable<WikiResults> {
override fun deserialize(reader: Reader): WikiResults? {
return Gson().fromJson(reader, WikiResults::class.java)
}
}
Normally, I would to have Gson() recognised by IDE and I wound be able to call .fromJson() normally. Gradle was downloaded properly. (I don't have any message error about).
Using this Lib in your gradle:
dependencies{
implementation 'com.google.code.gson:gson:2.8.2'
}
The problem is probably in dependency of fuel-gson:2.2.0
To bypass it, I added a new dependency to my build.gradle manually and problem is solved.
dependencies {
implementation 'com.google.code.gson:gson:2.8.5'
}
Its may happen due to different versions of gson in External Libraries. To resolve it I have added following resolveStrategy in app module build.gradle.
configurations.all {
resolutionStrategy.preferProjectModules()
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == 'com.google.code.gson') {
details.useVersion "2.8.5"
}
}
}
Related
Module replacement works well in Gradle, however it only applies when there is a conflict.
Although I understand the reason, it breaks my use-case where there is extension of configurations and the conflict happens in some but not others that I need to consume.
I have two special configurations and some module replacement:
configurations {
lib // what should be bundled
provided // what should not be bundled
implementation.extendsFrom(lib)
implementation.extendsFrom(provided)
}
dependencies {
modules {
module('javax.annotation:javax.annotation-api') {
replacedBy('jakarta.annotation:jakarta.annotation-api', 'Javax to Jakarta')
}
}
}
task collectLibs(type: Copy) {
// bundle everything from lib which is not provided (not even transitively)
from configurations.lib - configurations.provided
into "$buildDir/lib"
}
I also use company BOM, here for example: api platform('org.springframework.boot:spring-boot-dependencies:2.5.4') and so I don't want to specify versions anywhere in my project.
Let's assume these dependencies:
dependencies {
lib 'javax.annotation:javax.annotation-api'
provided 'jakarta.annotation:jakarta.annotation-api'
}
the task dependencies then correctly resolves compileClasspath and runtimeClasspath to jakarta.annotation-api, however the collected files in build/lib contain javax.annotation-api-1.3.2.jar even though it "should have been replaced and subtracted"
If I use module substitution instead, it works:
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute module('javax.annotation:javax.annotation-api') using module('jakarta.annotation:jakarta.annotation-api:1.3.5')
}
}
However there I must specify version. Is there any possibility to force module replacement to always act?
My problem is caused by the subtraction, maybe there is a better way to find all dependencies that come from provided but not lib by looking at runtimeClasspath?
I tried something but it gets too complicated very quickly.
I found a solution. Instead of subtracting provided configuration, I can exclude everything from resolved provided configuration. The tricky part is to exclude not too much and not too little:
platform must remain otherwise resolution of versions will fail
both requested and selected must be excluded
This is not a general solution; it still requires some fiddling with configurations (provided must declare both javax and jakarta) but it works for me.
private static excludeFromConfiguration(Configuration configuration, Configuration toExclude) {
toExclude.incoming.resolutionResult.allDependencies.each { dep ->
if (dep instanceof ResolvedDependencyResult && dep.requested instanceof ModuleComponentSelector) {
def isPlatform = dep.requested.attributes.keySet().any {
// asking for org.gradle.api.attributes.Category.CATEGORY_ATTRIBUTE does not work
def attribute = dep.requested.attributes.getAttribute(it)
return attribute == org.gradle.api.attributes.Category.ENFORCED_PLATFORM ||
attribute == org.gradle.api.attributes.Category.REGULAR_PLATFORM
}
if (!isPlatform) {
// we exclude both - the requested and selected because there could have been some:
// module replacement, dependency substitution, capability matching
configuration.exclude(group: dep.requested.group, module: dep.requested.module)
configuration.exclude(group: dep.selected.moduleVersion.group, module: dep.selected.moduleVersion.name)
}
}
}
}
Trying to communicate with LibGDX project per Javascript with JsInterop. I am following the "Exporting a Java type to JavaScript" example here. It does not work: Uncaught ReferenceError 'com' is not defined. I am not getting any errors with gradle though.
I have already:
checked that generateJsInteropExports is enabled:
My GdxDefinition.gwt.xml:
<module rename-to="html">
<inherits name='com.badlogic.gdx.backends.gdx_backends_gwt' />
<inherits name='com.badlogic.gdx.physics.box2d.box2d-gwt' />
<inherits name='myapp' />
<entry-point class='com.mypackage.myapp.client.HtmlLauncher' />
<set-configuration-property name="gdx.assetpath" value="../android/assets" />
<set-configuration-property name='xsiframe.failIfScriptTag' value='FALSE'/>
<set-configuration-property name='generateJsInteropExports' value='true'/>
<set-property name="user.agent" value="safari"/>
</module>
I was thinking, maybe the entry point HtmlLauncher should be also a #JsType, but this did not work either.
Also checked that generateJsInteropExports is enabled in GdxDefinitionSuperdev.gwt.xml
Accessing the class in the browser console in different ways like:
.
new com.mypackage.myapp.client.Test();
new Test(); // when setting namespace to global
$wnd.Test(); // JSNI syntax
I am compiling like that:
gradlew.bat html:dist --daemon -generateJsInteropExports=true
My class (Right in the html module, also tried in core module, still does not work) looks like that:
package com.mypackage.myapp.client;
import jsinterop.annotations.JsPackage;
import jsinterop.annotations.JsType;
#JsType(namespace = JsPackage.GLOBAL)
public class Test {
public String name;
public Test(String name) {
this.name = name;
}
public void sayHello() {
return "Hello" + this.name;
}
}
I am running out of ideas. Can somenody help me figuring out what to do so that it works.
Some information that might be useful:
Code from my html.gradle:
gwt {
gwtVersion='2.8.0' // Should match the gwt version used for building the gwt backend
//...
modules 'com.mypackage.myapp.GdxDefinition'
devModules 'com.mypackage.myapp.GdxDefinitionSuperdev'
project.webAppDirName = 'webapp'
compiler {
strict = true;
disableCastChecking = true;
}
}
import org.wisepersist.gradle.plugins.gwt.GwtSuperDev
//...
task superDev (type: GwtSuperDev) {
dependsOn startHttpServer
doFirst {
gwt.modules = gwt.devModules
}
}
//...
Code from my project gradle
buildscript {
//...
dependencies {
classpath 'org.wisepersist:gwt-gradle-plugin:1.0.6'
//...
}
}
project(":html") {
apply plugin: "gwt"
apply plugin: "war"
dependencies {
compile project(":core")
compile "com.badlogicgames.gdx:gdx-backend-gwt:$gdxVersion"
compile "com.badlogicgames.gdx:gdx:$gdxVersion:sources"
compile "com.badlogicgames.gdx:gdx-backend-gwt:$gdxVersion:sources"
compile "com.badlogicgames.gdx:gdx-box2d:$gdxVersion:sources"
compile "com.badlogicgames.gdx:gdx-box2d-gwt:$gdxVersion:sources"
compile "com.google.jsinterop:jsinterop-annotations:1.0.1"
}
}
project(":core") {
apply plugin: "java"
dependencies {
//...
compile "com.google.jsinterop:jsinterop-annotations:1.0.1"
}
}
//...
UPDATE 1
I checked Colin Alworth's answer and the links he posted. It still does not work. I changed:
html.gradle
gwt {
gwtVersion='2.8.0' // Should match the gwt version used for building the gwt backend
maxHeapSize="1G" // Default 256m is not enough for gwt compiler. GWT is HUNGRY
minHeapSize="1G"
src = files(file("src/")) // Needs to be in front of "modules" below.
modules 'com.mycompany.myapp.GdxDefinition'
devModules 'com.mycompany.myapp.GdxDefinitionSuperdev'
project.webAppDirName = 'webapp'
compiler {
strict = true;
disableCastChecking = true;
}
jsInteropExports {
shouldGenerate = true
includePatterns = ['com.mycompany.myapp.client.*']
}
}
Like it says here.
I call like: gradlew.bat html:dist --daemon and I removed the property generateJsInteropExports from GdxDefinition files since it seems wrong.
Now I get following compilation error:
Task :html:compileGwt FAILED
Unknown argument: -includeJsInteropExports
Why is that?
Big thanks to #Colin Alworth, I found out how to get it work.
html.gradle
gwt {
gwtVersion='2.8.0' // Should match the gwt version used for building the gwt backend
maxHeapSize="1G" // Default 256m is not enough for gwt compiler. GWT is HUNGRY
minHeapSize="1G"
src = files(file("src/")) // Needs to be in front of "modules" below.
modules 'com.mycompany.myapp.GdxDefinition'
devModules 'com.mycompany.myapp.GdxDefinitionSuperdev'
project.webAppDirName = 'webapp'
compiler {
strict = true;
disableCastChecking = true;
}
// important part:
jsInteropExports {
shouldGenerate = true
// breaks if I use includePatterns
}
}
And also
remove <set-configuration-property name='generateJsInteropExports' value='true'/> from Gdx definition files
Not use same name in global namespace for exported classes (stupid mistake, I know)
Compile call like gradlew.bat html:dist --daemon
And the perfect result:
<set-configuration-property name='generateJsInteropExports' value='true'/>
This definitely will not work to generate those exports
gradlew.bat html:dist --daemon -generateJsInteropExports=true
I don't know gradle terrible well, but I'm all but certain this is wrong too (at least it needs a -P prefix, but I don't see that property being used in the gradle file you shared).
Instead, you need to need to pass it to your gradle plugin, both for Super Dev Mode and for the production compile task.
From a quick glance at the docs for org.wisepersist:gwt-gradle-plugin, it looks like the task will take a GwtJsInteropExportsOptions arg (working from http://gwt-gradle-plugin.documentnode.io/javadoc/org/wisepersist/gradle/plugins/gwt/GwtJsInteropExportsOptions.html and http://gwt-gradle-plugin.documentnode.io/javadoc/org/wisepersist/gradle/plugins/gwt/AbstractGwtActionTask.html#setJsInteropExports-org.wisepersist.gradle.plugins.gwt.GwtJsInteropExportsOptions-), which in my limited gradle experience will end up something like
jsInteropExports {
generate = true
}
It looks like this can go in the gwt {} block, alongside compiler {}.
Here's an issue on that plugin's tracker which discusses how to do this https://github.com/jiakuan/gwt-gradle-plugin/issues/19.
SpringBoot comes with a lot of dependencies plus default versions for them.
In groovy-gradle, such dependency versions can be overridden with:
ext['mockito.version'] = '1.7.5'
But this doesn't work for the kotlin-dsl.
I tried:
val mockito by extra { "2.12.0" }
val mockito.version by extra { "2.12.0" }
val `mockito.version` by extra { "2.12.0" }
The latter two, don't compile, the first one, isn't doing the job.
How can the version be overridden within the kotlin file (I don't want to create a separate properties file if it is somehow possible).
Try extra["mockito.version"] = "1.7.5"
Background: Running Android Studio 3.0-beta7 and trying to get a javadoc task to work for an Android library (the fact that this is not available as a ready-made task in the first place is really strange), and I managed to tweak an answer to a different question for my needs, ending up with this code (https://stackoverflow.com/a/46810617/1226020):
task javadoc(type: Javadoc) {
failOnError false
source = android.sourceSets.main.java.srcDirs
// Also add the generated R class to avoid errors...
// TODO: debug is hard-coded
source += "$buildDir/generated/source/r/debug/"
// ... but exclude the R classes from the docs
excludes += "**/R.java"
// TODO: "compile" is deprecated in Gradle 4.1,
// but "implementation" and "api" are not resolvable :(
classpath += configurations.compile
afterEvaluate {
// Wait after evaluation to add the android classpath
// to avoid "buildToolsVersion is not specified" error
classpath += files(android.getBootClasspath())
// Process AAR dependencies
def aarDependencies = classpath.filter { it.name.endsWith('.aar') }
classpath -= aarDependencies
aarDependencies.each { aar ->
System.out.println("Adding classpath for aar: " + aar.name)
// Extract classes.jar from the AAR dependency, and add it to the javadoc classpath
def outputPath = "$buildDir/tmp/exploded-aar/${aar.name.replace('.aar', '.jar')}"
classpath += files(outputPath)
// Use a task so the actual extraction only happens before the javadoc task is run
dependsOn task(name: "extract ${aar.name}").doLast {
extractEntry(aar, 'classes.jar', outputPath)
}
}
}
}
// Utility method to extract only one entry in a zip file
private def extractEntry(archive, entryPath, outputPath) {
if (!archive.exists()) {
throw new GradleException("archive $archive not found")
}
def zip = new java.util.zip.ZipFile(archive)
zip.entries().each {
if (it.name == entryPath) {
def path = new File(outputPath)
if (!path.exists()) {
path.getParentFile().mkdirs()
// Surely there's a simpler is->os utility except
// the one in java.nio.Files? Ah well...
def buf = new byte[1024]
def is = zip.getInputStream(it)
def os = new FileOutputStream(path)
def len
while ((len = is.read(buf)) != -1) {
os.write(buf, 0, len)
}
os.close()
}
}
}
zip.close()
}
This code tries to find all dependency AAR:s, loops through them and extracts classes.jar from them, and puts them in a temp folder that is added to the classpath during javadoc generation. Basically trying to reproduce what the really old android gradle plugin used to do with "exploded-aar".
However, the code relies on using compile dependencies. Using api or implementation that are recommended with Gradle 4.1 will not work, since these are not resolvable from a Gradle task.
Question: how can I get a list of dependencies using the api or implementation directives when e.g. configuration.api renders a "not resolvable" error?
Bonus question: is there a new, better way to create javadocs for a library with Android Studio 3.0 that doesn't involve 100 lines of workarounds?
You can wait for this to be merged:
https://issues.apache.org/jira/browse/MJAVADOC-450
Basically, the current Maven Javadoc plugin ignores classifiers such as AAR.
I ran in to the same problem when trying your answer to this question when this error message kept me from resolving the implementation dependencies:
Resolving configuration 'implementation' directly is not allowed
Then I discovered that this answer has a solution that makes resolving of the implementation and api configurations possible:
configurations.implementation.setCanBeResolved(true)
I'm not sure how dirty this workaround is, but it seems to do the trick for the javadocJar task situation.
I Have a task from my plugin that need mysql or postgres drivers.
currently I hardcoded into FooPlugin::apply method this:
configuration.dependencies.add(project.dependencies.create('mysql:mysql-connector-java:5.1.34'))
But I would like to let users, to choose their drivers.
So for this I would like to grab all dependencies from gradle build script (build.gradle) which applying my plugin to inject these dependencies to the task dynamically.
Resolved: add a piece of code
I tried this:
class FooPlugin implements Plugin<Project>{
#Override
void apply(Project project) {
project.afterEvaluate {
def configuration = project.configurations.create('bar')
configuration.extendsFrom(project.configurations.findByName('compile'))
…
}
}
}
If you do not put into project.afterEvaluate block below error is raised:
Cannot change dependencies of configuration ':bar' after it has been resolved.
I'm not sure exactly what your trying to accomplish so I'm going to guess at a couple things.
Looks like your trying to add a dependency or react based on a dependency added. I think you can accomplish either through the resolutionStrategy
project.configurations {
compile.resolutionStrategy {
// adds a dependency to a project, always.
force 'commons-io:commons-io:2.5'
// loop through all the dependencies to modify before resolution
eachDependency { DependencyResolveDetails details ->
// here you can change details about a dependency or respond however needed
if (details.requested.group == 'mysql' && details.requested.name == 'mysql-connector-java') {
// for example we can force a specific version
details.useVersion '5.1.34'
}
// you could also add a if block for postgres if needed
}
}
}