mirror of
https://github.com/apple/pkl.git
synced 2026-01-11 14:20:35 +01:00
codegen-java: Support generating @Nullable annotations #250
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @odenix on GitHub (Nov 14, 2024).
Motivation:
codegen-java already supports generating
@NonNullannotations.However, many projects prefer
@Nullableover@NonNullannotations.JSpecify also recommends
@Nullable.Changes:
--nullable-annotationCLI parameter that defaults tonone.nullableAnnotationGradle/CliJavaCodeGenerator/JavaCodeGenerator property that defaults tonull.As part of this feature, I propose to also make the following changes:
-non-null-annotationCLI parameter andnonNullAnnotationproperties accordingly.@NonNullannotations by default.org.pkl.java.config.mapper.NonNulland encourage users to switch to JSpecify.Note that tools won't recognize
org.pkl.java.config.mapper.NonNullunless explicitly configured.Open question:
@Nullablemust be accompanied by@NullMarked(JSpecify) or@NonnullByDefault(JSR 305).I can think of two ways to go about this:
--null-marked-annotationand annotate config classes accordingly.This is the most consistent solution, but it requires yet another CLI parameter and property.
It can be made more convenient by inferring the correct annotation based on
--nullable-annotationand--non-null-annotationfor popular libraries such as JSpecify and JSR 305.package-info.javawith a@NullMarkedannotation.This is a clean and simple solution. However, it is less convenient than (1).
It could, in theory, cause problems if users compile generated and handwritten code separately and don't have a place where to put
package-info.java.Final thought: The Java ecosystem is converging on JSpecify. For many users, the best option would be
--generate-jspecify-annotations.@holzensp commented on GitHub (Dec 2, 2024):
I agree with the overall approach. With JSpecify gaining traction, it's a reasonable choice (and any somewhat popular annotation framework is better than bespoke annotations, because of the "unless explicitly configured").
It seems cleaner to me to end up with a single CLI parameter and property, that picks the flavor, rather than a parameter and property per flavor. I like
--nullable-annotation(or--nullability-annotationto avoid the implication that it's only about annotating the nullable case, rather than the non-nullable case).I agree with your cost balancing assessment between (1) and (2), and I do like clean and simple. However, I think it's more important that our generated code is correct by default and (2) does leave awkward ways to hold it wrong. I prefer (1).
Let's have @stackoverflow & @bioball chime in also.
@odenix commented on GitHub (Dec 12, 2024):
Can you clarify what you’re proposing here?
@bioball commented on GitHub (Dec 13, 2024):
I think maybe a better solution is to let users configure what library they want their nullness annotations to come from (this is maybe what @holzensp is talking about too). Something like:
--nullable-annotation=jsr305|jspecify|pkl.But, another issue here is that JSR305 doesn't actually have a
NonnullByDefaultannotation. The closest thing isParametersAreNonnullByDefault, but that only covers method parameters, and not fields nor method return types. For the JSR305 case, I think we'd need to do something like: also generate a@NonnullByDefaultannotation class that can applied to the class.This doesn't seem like a great solution; it feels like we'd be generating incomplete code.
Also, FWIW: I'm not sure how big of a problem this is, and at the same time, adds a lot of complexity to our code generator. It might be good to hold off for some more +1's from the community.
@odenix commented on GitHub (Dec 13, 2024):
Not supporting
@Nullable/@NullMarkedmeans not supporting the recommended way to use jspecify. I’ve yet to see a project that uses jspecify and doesn’t use@Nullable/@NullMarked. If you think a generic solution is too complex, we should at least support this mode for jspecify. jsr305 is dead, and I don’t think it needs to be considered other than keeping the existing support.Pkl’s
@NonNullannotation should be deprecated as tools won’t understand it.@bioball commented on GitHub (Dec 13, 2024):
I don't think this needs to be deprecated; tools like IntelliJ let you configure nullability annotations. The intention here is that, by default, Pkl's generated code does not require any dependencies.
Yeah, fair. I think we can have two flags; the nullability library to use, and whether to generate nullable-by-default annotations.
And we can throw if the nullability mode is non-null-by-default if targeting JSR305; e.g. throw here:
@odenix commented on GitHub (Dec 14, 2024):
It doesn’t need to be, but users who care about nullness annotations should be strongly encouraged to use one of the widely supported libraries instead of configuring Pkl’s proprietary
@NonNull. And users who don’t care about nullness annotations won’t miss Pkl’s@NonNulleither.Given that we already have
—non-null-annotation=fqcn, the most consistent solution would be to support—nullable-annotation=fqcnand support combining them. If only—nullable-annotation=org.jspecify.annotations.Nullableis specified, we know that we must also add@NullMarked. We could supportjspecifyandjsr305as shorthands for the fqcn’s.@bioball commented on GitHub (Dec 22, 2024):
I'm okay with switching the default to be JSpecify, but I'd prefer to keep around the current annotations as an alternative. We have users that are sensitive to new dependencies, so it would be good to provide options to those that don't want to incur a new dependency here. But, yeah, in principle, I agree that people that care about nullable annotations would want to use a known library.
Your suggestion seems a little quirky to me; it allows for someone to choose
--nullable-annotation=jspecify --non-null-annotation=jsr305, which there isn't a real-world use for.I feel that deprecating
--non-null-annotationand introducing two new flags feels like the better approach. But, I also don't feel that strongly about this, and I'm okay with accepting a PR for either approach.@edward3h commented on GitHub (Sep 8, 2025):
I came looking to see if there was an issue for this already. +1 for JSpecify support.
I'm working on a project which already has JSpecify @NullMarked and @Nullable, so the mismatch is frustrating.
Separately, I made an annotation processor that generates
package-info.javawith @NullMarked, where necessary, so I'm not concerned about whether Pkl would generate it.