Cannot set the value of read-only property 'group' for DefaultExternalModuleDependency - android

I am solving duplicate issue due build process caused by a new library. There are some duplicate classes or a whole package of bouncycastle. The issue is the default way to exclude a class or a whole group brings this issue:
Caused by: groovy.lang.GroovyRuntimeException: Cannot set the value of read-only property 'group' for DefaultExternalModuleDependency{group='org.web3j', name='core', version='4.8.7-android', configuration='default'} of type org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency
Code itself:
implementation('org.web3j:core:4.8.7-android') {
exclude(group = 'org.bouncycastle')
}
Is there some changes in exclude usage over the past few years?

It's just a syntax issue, the exclude method expects a Map parameter. it looks like you are using the Groovy DSL, and in Groovy maps are created using : character ( in Kotlin DSL you would use = as you did)
So just replace = assignement by : as follows:
implementation('org.web3j:core:4.8.7-android') {
exclude(group : 'org.bouncycastle')
}
See some examples here https://docs.gradle.org/current/userguide/dependency_downgrade_and_exclude.html#sec:excluding-transitive-deps

Related

Android: Add maven-publish configuration in a separate kotlin dsl script

I've written a .gradle script named publish.gradle which configures publishing {} for releasing my artifact.
Why on a separate script? I have multiple modules and by doing this every releasable module simply defines some variables.
Module build.gradle.kts:
// Module's blah blah
apply(from = "../publish.gradle")
publish.gradle:
apply plugin: 'maven-publish'
publishing {
publications {
// configure release process
}
}
I've recently decided to migrate to Gradle Kotlin DSL. However, there's an issue:
Adding publication {} like this:
plugins {
`maven-publish`
}
publication {
}
Lead to this error:
Expression 'publishing' cannot be invoked as a function. The function 'invoke()' is not found
Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public val PluginDependenciesSpec.publishing: PluginDependencySpec defined in org.gradle.kotlin.ds
Which is summarized to
PluginDependenciesSpec is not present as a receiver
What is the difference?
TL; DR
I've added publishing {} config to a separate script which works when in .gradle groovy format but I can not convert to .gradle.kts kotlin format. The publishing is extension of PluginDependenciesSpec class which is not present in the script.
Here's what worked for me:
plugins {
id("maven-publish")
}
configure<PublishingExtension> {
publications.create<MavenPublication>("myPlugin") {
groupId = "com.myCompany.android"
artifactId = "MyPlugin"
version = "1.0.0"
pom.packaging = "jar"
artifact("$buildDir/libs/MyPlugin.jar")
}
repositories {
mavenLocal()
}
}
I understand where you're coming from, converting from groovy to kotlin script is not a simple one to one translation, and most of us, including myself, code by example. In other words, you just need to see a simple example and you can figure out the rest. This works great when examples are readily available. What you need to do when you don't find an example is to turn to the API document. For example, https://docs.gradle.org/current/dsl/org.gradle.api.publish.PublishingExtension.html shows you the available properties for the PublishingExtension and you can keep drilling in to see what properties you have at the next level. This is especially important when examples may be working with an older version and may no longer be applicable. I will say that it wasn't as obvious is that for accessing extensions in kotlin script, requires the configure block. That's a big difference, but I like that approach, because it makes it clearer what the extension properties are a part of. And by the way, kotlin wants double quote, single quotes are no longer acceptable.

Kotlin DSL add new sourceSet

On Gradle 6.1.1, how to go around adding sourceSets for android project?
The answer on other questions doesn't work anymore, getByName("name") returns error with SourceSet with name 'main' not found.
The official document said to use
sourceSets {
main {
java {
srcDir("thirdParty/src/main/java")
}
}
}
However, there are over 20 main that has to be imported and I'm not sure which one is correct.
I'm using gradle 6.5.1, however documentation suggest, that is should also work for you, try:
sourceSets {
named("main") {
java.srcDir("../buildSrc/src/main/java")
}
}
It's also works for build types (debug/release), flavours etc.
Reason for this is that groovy can somehow interpret itself and knows main etc., but on gradle kts, you have call it using named for already existing, or getByName, create etc. base on need.
Similiar situation is for implement and api in groovy you can just use implementationDebug to attach it only for debug version, but in kotlin dsl you have to call it as a string "implementationDebug", because there is no such function
----- PS -----
If named, getByName not works for you, then try to experiment with findByName and create

Gradle error debugCompileClasspath' to contain exactly one file, however, it contains no files, when adding a new Dynamic Feature Module

Created a new Dynamic Feature Module: dynamic, build fails with the below exception:
Execution failed for task ':dynamic:processDebugManifest'.
Expected configuration ':dynamic:debugCompileClasspath' to contain exactly one file, however, it contains no files.
Tried adding baseFeature true to the app gradle, and getting error:
Could not find method baseFeature() for arguments [true] on object of type com.android.build.gradle.internal.dsl.BaseAppModuleExtension.
I solved this, you need to have all flavors of the base module in your dynamic feature module also
I had the same error message but the problem was with the common KTS script I was using across the feature modules:
This was wrong:
private fun Project.configureDependencies() {
dependencies.project(":app")
}
This was right:
private fun Project.configureDependencies() = dependencies{
add("implementation", project(":app"))
}
Hope this helps some poor soul

sbt-android: unable to use scala-reflect on android: java.rmi.Remote not found

I'm trying to use the scala-reflect package for android development.
I have added the scala-reflect dependency in my build.sbt:
libraryDependencies += "org.scala-lang" % "scala-reflect" % "2.11.8"
but I get an exception:
java.lang.NoClassDefFoundError: Failed resolution of: Ljava/rmi/Remote;
at scala.reflect.internal.Definitions$DefinitionsClass.RemoteInterfaceClass$lzycompute(Definitions.scala:370)
at scala.reflect.internal.Definitions$DefinitionsClass.RemoteInterfaceClass(Definitions.scala:370)
at scala.reflect.runtime.JavaUniverseForce$class.force(JavaUniverseForce.scala:255)
at scala.reflect.runtime.JavaUniverse.force(JavaUniverse.scala:16)
at scala.reflect.runtime.JavaUniverse.init(JavaUniverse.scala:147)
at scala.reflect.runtime.JavaUniverse.<init>(JavaUniverse.scala:78)
at scala.reflect.runtime.package$.universe$lzycompute(package.scala:17)
at scala.reflect.runtime.package$.universe(package.scala:17)
I have tried to add the java source of java.rmi.Remote and java.rmi.RemoteException and built the project with android:package --core-library (because sbt has not found the dexCoreLibrary option) , it builded successfully, but I got the runtime error.
So, is it possible to add the java.rmi dependency otherwise, that scala.reflect can use it?
I'm using the scala.reflect library in the context of an implementation of a method Option.orDefault:
class RichOption[+A : TypeTag](val delegate: Option[A]) {
def orDefault : A = delegate.getOrElse {
delegate match {
case t if typeOf[A] <:< typeOf[Int] => 0.asInstanceOf
case _ => throw new IllegalAccessException("there is no default value for this type.")
}
}
}
If you know a better implementation for Option.orDefault
(possibly without scala.reflect), please let me know.
Much better:
case class Default[A](value: A)
object Default {
implicit val intDefault: Default[Int] = Default(0)
// other Default implementations
}
class RichOption[+A](val delegate: Option[A])(implicit d: Default[A]) {
def orDefault : A = delegate.getOrElse(d.value)
}
You get a compilation error instead of a runtime error if used with a type which doesn't have a defined default value, no complex matching, no need for a large dependency, etc.

PackageNameSuffix breaks test - Robolectric

When I add a packageNameSuffix to my build.gradle debug build type (see https://plus.google.com/108967384991768947849/posts/XGXH3arvbrK), all of my Robolectric tests are failing due to the following:
Caused by: android.content.res.Resources$NotFoundException: Unable to find resource ID #0x7f050000
at org.robolectric.shadows.ShadowResources.getResName(ShadowResources.java:354)
at org.robolectric.shadows.ShadowResources.openRawResource(ShadowResources.java:387)
at android.content.res.Resources.openRawResource(Resources.java)
at com.myapp.utilities.CSVUtility.parseRawResourceCSV(CSVUtility.java:38)
The problem seems to be that the raw folder src/main/res/main no longer being found. This folder contains a csv which is parsed at application start... which is where the tests go boom.
Architecture/data restructuring suggestions aside (I know CSV may not be the best way to get this data loaded at app start), does anyone know how I might remedy this problem?
Edit: I tried moving the file to the assets folder instead, and then my tests failed on a Context.getString() call. Resources look to be getting completely hosed when adding packageNameSuffixes.
Edit: tmurakami posted on the github issue - https://github.com/robolectric/robolectric/issues/1001#issuecomment-42740897
I've copied the full response:
Try using this gradle snippet.
This works fine in my environment.
def hasLibraryVariants = android.hasProperty('libraryVariants')
def variants = hasLibraryVariants ? android.libraryVariants : android.applicationVariants
tasks.withType(Test).whenTaskAdded {
it.systemProperty 'android.package', variants.iterator().next().processResources.packageForR
}
The original package name has been stored in the following fields of any variant:
variantData.variantConfiguration.originalPackageName
processResources.packageForR
generateBuildConfig.buildConfigPackageName
However these are internal only, so might become inaccessible in the future.
If you don't want to use these fields, try the following snippet:
tasks.withType(Test).whenTaskAdded {
it.systemProperty 'android.package', android.defaultConfig.packageName
}
To use this, you need to add the main package name in the 'android.defaultConfig' section.
android {
defaultConfig {
packageName 'main.package.name'
}
}
Looks like I need to add an android.package system property for the package name. See this issue conversation on Github - https://github.com/robolectric/robolectric/issues/1001

Categories

Resources