Skip to content

Conversation

@frevib
Copy link

@frevib frevib commented Jan 5, 2026

What is the purpose of the change

Gradle plugin to generate Java code from Avro files

Verifying this change

This change added tests and can be verified as follows:

cd to avro/lang/java/gradle-plugin

./gradlew test

Documentation

Release

BETA 0.0.2 is released and fully works with AVSC files: https://central.sonatype.com/artifact/eu.eventloopsoftware.avro-gradle-plugin/eu.eventloopsoftware.avro-gradle-plugin.gradle.plugin/versions - read docs (above) how to use

BETA 0.0.5 https://plugins.gradle.org/plugin/eu.eventloopsoftware.avro-gradle-plugin

An official release will be done in the coming month

frevib added 2 commits January 5, 2026 16:30
Cleanup readme

Change POM artifactId name
@github-actions github-actions bot removed the website label Jan 5, 2026
Cleanup
fun compileSchema() {
project.logger.info("Generating Java files from Avro schemas...")

if (!source.isEmpty) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If something like DirectoryProperty is used in conjunction with @SkipWhenEmpty , a task state of NO_SOURCE should be used when no sources are available.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can we log some useful message when we use @SkipWhenEmpty and no sources are available? Now we have the else branch where we log.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to? Other Gradle tasks (compileJava, compileTestJava etc) don't warn when no sources are available.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From a code point of view, if @SkipWhenEmpty is more idiomatic Gradle, I understand. But we should care about user experience. It will improve UX If the user directly sees why no code was generated because e.g. a wrong directory was provided.

For Intellij to recognize the newly generated Java files add this to `build.gradle.kts`:

```kotlin
tasks.named("compileKotlin") { dependsOn(tasks.named("avroGenerateJavaClasses")) }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the jank that can be avoided by setting the srcDir using the task to avoid requiring dependsOn fixes https://github.com/apache/avro/pull/3614/changes#r2662114325

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compilation fails if we don't use that line. Unresolved reference 'SomeGeneratedClass.

I've used your method of adding sources: https://github.com/apache/avro/pull/3614/files#diff-02e299025197282b1f1fec4a0fe89c1fb47606fcd9a2b0fc55206ca1ae8f511dR75

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works: 3853d9a#diff-6f6c17b901d3a280371d65a7c7907afd0275f06f4dd28682c65343c4a92a97ebR40

No need to add tasks.named("compileKotlin") { dependsOn(tasks.named("avroGenerateJavaClasses")) } any more. Thanks for pointing it out 🙏


#### How can I benefit from Kotlin's null safety?
Use `createNullSafeAnnotations = true` and Java getters will be annotated with
`@org.jetbrains.annotations.NotNull`/ `@org.jetbrains.annotations.Nullable`. This way
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gradle has finished migrating to jspecify, Kotlin 2.+ also supports jspecify annotations. Perhaps those should be used by default instead of jetbrains'?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although JSpecify seems to become the new standard, I'd be hesitant to make this change yet for the Maven plugin.

Here though, as both Gradle and Kotlin are moving in this direction and this plugin is new, I think the JSpecify annotations are a good default to use.

Kotlin will recognize which value is nullable.

#### When I update my schemas and generate code, the Java classes stay the same
Yes, for now you have to `./gradlew clean` every time you update your Avro schemas.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should clear controlled output directories (outputDir/testOutputDir) instead of requiring the user to do so.

import org.gradle.api.tasks.Input
import org.gradle.api.tasks.SourceTask

abstract class AbstractCompileTask : SourceTask() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gradle's SourceTask is probably not the preferred superclass for this task, that's usually used for things like compilation, analysis. I'd recommend DefaultTask.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DefaultTask is being deprecated. Why is SourceTask not preferred? From the docs: A {@code SourceTask} performs some operation on source files, which is kind of what we're doing.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've not seen anything that would indicate DefaultTask being deprecated, and I can't imagine they could considering how many tasks already inherit directly from DefaultTask.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's an error on my side, DefaultTask is indeed not being deprecated.

Anyway, with DefaultTask we don't have source, setIncludes(..) and setExcludes(..)which are very useful in filtering for specific Avro file extension like "**/*.avsc". Then we have to manually filter the FileTree for Avro file extensions. Do you still recommend it?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'm starting to understand why SourceTask is maybe not the right fit. We now use source and sourceDirectory, which are used for the same things. If we use DefaultTask we don't have the issue of this ambiguity, and only use sourceDirectory


@TaskAction
fun compileSchema() {
project.logger.info("Generating Java files from Avro schemas...")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be using the task's logger, not the project's logger. I also don't think these logs provide any useful information.



private fun getSourceDirectoryFullPath(directoryProperty: Property<String>): File =
project.layout.projectDirectory.dir(directoryProperty.get()).asFile
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling project at runtime is soft-deprecated in Gradle 8, deprecated in Gradle 9 and will be unsupported in Gradle 10. https://docs.gradle.org/8.12.1/userguide/configuration_cache.html#config_cache:requirements:use_project_during_execution

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be avoided by using DirectoryPropertys, which would already be project-relative.

frevib added 7 commits January 6, 2026 09:16
Use directory property instead of Property<String>
Rename classes
Remove unneeded file which is generated by the java-gradle-plugin
Use Task logger instead of project logger
Fix comment
Refactor adding sources
Add custom logical type factories
name = "Avro Gradle Plugin"
description = "Generate Java code from Avro files"
inceptionYear = "2025"
url = "https://github.com/frevib/avro/"
Copy link
Contributor

@opwvhk opwvhk Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
url = "https://github.com/frevib/avro/"
url = "https://github.com/apache/avro/"

For the non-beta release (and below)

* at schema compiling time. All files can therefore be referenced as classpath
* resources following the directory structure under the source directory.
*
* @parameter property="sourceDirectory"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use the Maven annotations instead? IMHO they're easier to read (less likely to be missed when reading the code).

Copy link
Contributor

@opwvhk opwvhk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good so far!

Update readme with versioning

New release: 0.0.5
@frevib
Copy link
Author

frevib commented Jan 7, 2026

New BETA 0.0.5release is now on Gradle plugin portal: https://plugins.gradle.org/plugin/eu.eventloopsoftware.avro-gradle-plugin.

frevib added 3 commits January 7, 2026 16:47
Remove Maven publishing, only publish in Gradle plugin registry
Add generated code before compilation, so no dependsOn(..) is needed any more
Release 0.0.7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build Java Pull Requests for Java binding

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants