Andreas Wenger
03/31/2024, 1:14 PMAndreas Wenger
03/31/2024, 1:14 PMProperty, ListProperty , ...). Similar to what is described here or here.
Are there any drawbacks to this approach? Should the properties be primitive types + lists only? Are there any restrictions?
B) Using Properties
I found this paragraph that seem to advocate for using Property, ListProperty, ...
> Java bean properties.
> Sometimes you may see properties implemented in the Java bean property style. That is, they do not use a PropertyT or ProviderT types but are instead implemented with concrete setter and getter methods (or corresponding conveniences in Groovy or Kotlin). This style of property definition is legacy in Gradle and is discouraged. Properties in Gradle’s core plugins that are still of this style will be migrated to managed properties in future versions.
Is there a good example that showcases the use of Properties with nested data structures?
C) Or maybe something completely different?Andreas Wenger
03/31/2024, 1:33 PMAsmClassVisitorFactory
If I use classes for the configuration with this structure:
open class AddTraceSpec @Inject constructor(objectFactory: ObjectFactory) {
val classes: Property<ClassMatcherSpec> = objectFactory
.property(ClassMatcherSpec::class.java)
.also { it.set(objectFactory.newInstance(ClassMatcherSpec::class.java)) }
val methods: ListProperty<MethodMatcherSpec> = objectFactory.listProperty(MethodMatcherSpec::class.java)
val trace: Property<TraceNameSpec> = objectFactory
.property(TraceNameSpec::class.java)
.also { it.set(objectFactory.newInstance(TraceNameSpec::class.java)) }
}
It fails during build, because it can not serialize the properties:
> Failed to transform classes.jar (project :feature:search) to match attributes {artifactType=android-dex, asm-transformed-variant=demoDebug, com.android.build.api.attributes.AgpVersionAttr=8.2.0, com.android.build.api.attributes.BuildTypeAttr=debug, com.android.build.api.attributes.ProductFlavor:contentType=demo, com.android.build.gradle.internal.attributes.VariantAttr=demoDebug, contentType=demo, dexing-enable-desugaring=true, dexing-enable-jacoco-instrumentation=false, dexing-is-debuggable=true, dexing-min-sdk=24, org.gradle.category=library, org.gradle.jvm.environment=android, org.gradle.libraryelements=jar, org.gradle.usage=java-runtime, org.jetbrains.kotlin.platform.type=androidJvm}.
> Could not isolate parameters com.android.build.gradle.internal.dependency.AsmClassesTransform$Parameters_Decorated@7847bca1 of artifact transform AsmClassesTransform
> Could not isolate value com.android.build.gradle.internal.dependency.AsmClassesTransform$Parameters_Decorated@7847bca1 of type AsmClassesTransform.Parameters
> Could not serialize value of type AddTraceSpecVampire
03/31/2024, 2:06 PMafterEvaluate that you should avoid wherever possible.Vampire
03/31/2024, 2:08 PMVampire
03/31/2024, 2:09 PMExtensionAware, because they will be anyway due to the decoration Gradle is doing.Andreas Wenger
03/31/2024, 3:03 PMinterface AddTraceSpec {
fun getTrace(): Property<TraceNameSpec>
fun getClasses(): Property<ClassMatcherSpec>
fun getMethods(): ListProperty<MethodMatcherSpec>
}
interface ClassMatcherSpec {
fun getType(): Property<TypeSpec>
fun getSuperTypes(): ListProperty<TypeSpec>
fun getAnnotationTypes(): ListProperty<TypeSpec>
}
interface TypeSpec {
fun getPackageName(): Property<String>
fun getName(): Property<String>
}
And a helper function that simplifies working with these interfaces?
fun addTrace(traceName: String? = null, action: Action<in AddTraceSpec>? = null) {
val traceSpec = objectFactory.newInstance(TraceNameSpec::class.java)
val classSpec = objectFactory.newInstance(ClassMatcherSpec::class.java)
val spec = objectFactory.newInstance(AddTraceSpec::class.java)
spec.getTrace().set(traceSpec)
spec.getClasses().set(classSpec)
spec.getMethods().set(mutableListOf())
action?.execute(spec)
traceSpecs.add(spec)
}
• Is there any up to date documentation about this approach? Or some sample project that is configured like this?
• Is there a simpler way to let gradle initialize the different Property fields? Or is it best practice to provide such helper methods, like addTrace that ensure the relevant Property fields are initialized?Vampire
03/31/2024, 5:05 PMAnd surprisingly very different to the docs 😰Shouldn't really be different to the docs. Maybe some are outdated. 🤷♂️ Or maybe some are written with keeping supporing ancient versions in mind when Gradle was less capable. 🤷♂️
Just to double check, this would be the correct approach?:"Correct" is very subjective in software development. But I'd say totally no! For example, not
fun getTrace(): but val trace:, ...
And whether you use properties for the complex types or not is more an architectural question.
For example if you want to set and / or wire ClassMatcherSpec#type as a whole it might be good to have it as Property.
If you just want it for nested structure, but only the innermost properties configurable / wireable, the type would directly be the subtype.
In the latter case iirc you would annotate it with @get:Nested so that Gradle can do the boilerplate for the nested type.Andreas Wenger
04/01/2024, 4:39 PM