Skip to content

[BUG] [JAVA-SPRING] 7.24.0: generated field-level @JsonInclude(NON_NULL) overrides project-wide ObjectMapper inclusion #24401

Description

@gs-covariance
Description

Since 7.24.0 (via #23993), JavaSpring/pojo.mustache emits @JsonInclude(JsonInclude.Include.NON_NULL) on every optional non-nullable field.

Field-level @JsonInclude takes precedence over the project ObjectMapper inclusion (e.g. Spring Boot's spring.jackson.default-property-inclusion=non_empty). On upgrade, projects with a stricter global setting silently observe a wire change: fields that were previously omitted (empty collections, empty strings) begin to serialize because per-field NON_NULL is looser than the project default.

What's the recommended path for consumers who need the project ObjectMapper to remain the source of truth for inclusion policy? Field-level @JsonInclude on generated models overrides any global setting, so projects relying on spring.jackson.default-property-inclusion (or an equivalent customizer) can no longer enforce it uniformly on generated types.

Reproduction (for context)

Spring Boot application.yml:

spring:
  jackson:
    default-property-inclusion: non_empty

Optional non-nullable String / List / Map<K,V> fields on a generated model. Response body on 7.23 omits empty values (global NON_EMPTY); on 7.24 emits "field": "", "list": [], "map": {} (field-level NON_NULL wins).

openApiNullable=false, Spring Boot 3.x, Jackson 2.x. Verified live.

Activity

Picazsoo commented on Jul 23, 2026

@Picazsoo
Contributor

Thanks for the report, you're right and this is a valid bug.

The field-level @JsonInclude(JsonInclude.Include.NON_NULL) added in 7.24.0 (via #23993) was meant to stop generated models from emitting explicit null for optional non-nullable fields. But hard-coding it at the field level is harmful for anyone running a stricter global policy like non_empty or non_default: it overrides the global ObjectMapper and starts emitting empty strings/collections/maps that were previously omitted.

This is already being discussed on #23976 (here and here).

The plan: make the annotation configurable, something like NON_NULL (default) / NON_EMPTY / NON_DEFAULT / none, where none generates nothing and defers fully to your global mapper. The contract only needs us to not emit explicit null for optional non-nullable fields, and NON_EMPTY/NON_DEFAULT already satisfy that. Obviously setting the policy to none reopens the original problem (optional non-nullable fields can serialize explicit null), but that becomes the user's explicit choice, so I think it's the right call.

In the meantime you can unblock yourself with a custom template. Copy pojo.mustache into your templateDirectory and remove the block emitting the annotation:

{{^isNullable}}
@JsonInclude(JsonInclude.Include.NON_NULL){{/isNullable}}

I'll tag you on the PR. Apologies for the inconvenience.

gs-covariance commented on Jul 23, 2026

@gs-covariance
Author

@Picazsoo No worries and thank you very much for the detailed response!

Picazsoo commented on Jul 23, 2026

@Picazsoo
Contributor

Hi @gs-covariance and @MarcRoser and @MelleD, thanks again for raising this. You were right, and here's the plan to fix it.

The problem

The hard-coded @JsonInclude(JsonInclude.Include.NON_NULL) (@field:JsonInclude in Kotlin) on properties overrides any stricter global mapper policy (NON_EMPTY / NON_DEFAULT) with no way to opt out. That's a clear regression.

Proposed changes

Two new config options:

  1. optionalNonNullPropertyJsonInclude (enum, default NON_NULL)

    • Values: NON_NULL / NON_EMPTY / NON_DEFAULT / NONE
    • Would set the @JsonInclude policy for optional, non-nullable properties, or NONE to not emit the annotation at all (so your global mapper config would apply).
    • Default NON_NULL would keep current behavior on upgrade.

    Under the hood, the resolved value would be written into a single universal vendor extension on the property, and the template would simply emit whatever that extension holds. The codegen would apply the global default only if that extension has not already been set manually on the property. So you get a clear precedence:

    • a manual per-property value (vendor extension set directly in the spec) always wins, otherwise
    • the global default from optionalNonNullPropertyJsonInclude is used.
  2. generateJsonIncludeAnnotations (boolean, default true)

    • When false, all policy @JsonInclude annotations (the ALWAYS/NON_NULL on required properties and the configured policy on optional non-nullable properties) would be omitted, so your global ObjectMapper configuration would win for those properties. This is the opt-out you asked for @MelleD.
    • The @JsonInclude(NON_ABSENT) on JsonNullable properties would not be affected by this flag and would still be emitted (see below).

Important scoping

A manual per-property override (the vendor extension set directly in the spec) would always win, for any property, required or optional, and regardless of the generateJsonIncludeAnnotations flag. If you set it explicitly, that is what gets emitted, full stop.

Everything below describes only the automatic behavior that kicks in when no manual override is present on the property.

By default (generateJsonIncludeAnnotations=true), the automatic per-property configurability / opt-out via optionalNonNullPropertyJsonInclude would apply only to optional properties. For required properties we would automatically emit an explicit @JsonInclude, because omitting it (or applying a stricter policy) would break the OpenAPI contract:

  • A required field must always be present in the serialized JSON. Under a global NON_EMPTY/NON_DEFAULT policy, a required empty collection/string/0/false would be silently dropped, violating required.
  • So required fields would get an explicit annotation that guarantees presence:
    • Kotlin required non-nullable would use ALWAYS (the Kotlin type already prevents null).
    • Java required non-nullable would use NON_NULL (Java can't type-prevent null; see the note at the end for why omission is the better failure mode than an explicit null), and required nullable would use ALWAYS (explicit null is valid and must be serialized).

If you set generateJsonIncludeAnnotations=false, this automatic contract protection is intentionally turned off as well: the automatic required-field annotations would also be dropped, and required fields would then fall back to your global mapper policy (unless you've set a manual per-property override). That is the full escape hatch for people who manage inclusion entirely via their global ObjectMapper, but be aware it re-introduces the footgun that a stricter global policy could silently omit a required empty value. It's opt-in and off by default for exactly that reason.

The one genuinely non-negotiable case

For openApiNullable=true, @JsonInclude(NON_ABSENT) on JsonNullable<T> fields would always be emitted, regardless of either option (including generateJsonIncludeAnnotations=false). It's not a policy choice, it's what makes JsonNullable distinguish absent from explicit null, so disabling it would break openApiNullable semantics entirely.

Summary matrix

Automatic defaults (when no manual per-property override is set and generateJsonIncludeAnnotations=true):

Property Nullable Kotlin (auto) Java (auto)
required non-nullable ALWAYS NON_NULL (see below)
required nullable ALWAYS ALWAYS
optional non-nullable NON_NULL (via optionalNonNullPropertyJsonInclude) NON_NULL (via optionalNonNullPropertyJsonInclude)
optional nullable (openApiNullable=true) NON_ABSENT NON_ABSENT

How the automatic defaults can be changed:

Mechanism Scope Effect
Manual per-property vendor extension any single property (required or optional) Always wins. Emits exactly the value you set, regardless of everything below.
optionalNonNullPropertyJsonInclude (NON_NULL/NON_EMPTY/NON_DEFAULT/NONE) all optional non-nullable properties Sets their automatic policy; NONE emits nothing.
generateJsonIncludeAnnotations=false all required + optional non-nullable properties Drops all automatic policy annotations (the required ALWAYS/NON_NULL and the optional policy). Does not affect NON_ABSENT on JsonNullable, and does not affect manual overrides.

NON_ABSENT on JsonNullable<T> (only present when openApiNullable=true) is always emitted and is not affected by any of the options above.

This makes the generated output respect global mapper config where it can, without weakening the contract where it can't. And you can always embrace the danger zone if you wish to.

Does this make sense? I think this should satisfy everyone and it should be very flexible. The need to introduce two config options is a bit troublesome but I cannot see a way to logically combine these into one without causing even more confusion.

In the meantime you can unblock yourself with a custom dataClassOptVar.mustache (Kotlin) / pojo.mustache (Java) that drops the @JsonInclude line so your global policy would apply again.

Thanks for all the sharp feedback and sorry once again for any inconvenience caused.

Why NON_NULL and not ALWAYS for Java required non-nullable

For Java required non-nullable, NON_NULL omits the field, which fails cleanly as a "missing required field" at the consumer boundary. ALWAYS would instead put "field": null on the wire, a positive, type-invalid assertion that a lenient consumer might accept and propagate. A missing required field is the safer, louder, more standard failure than an explicit null on a non-nullable field.

MelleD commented on Jul 24, 2026

@MelleD
Contributor

I wasn't right; rather, I had a hunch—or rather, experience—with annotations that they should be used with caution.

The @JsonInclude(NON_ABSENT) on JsonNullable properties would not be affected by this flag and would still be emitted (see below).

I checked my own code, and none of my DTOs—including those with JsonNullable—require any JsonInclude. I don’t have a single JsonInclude in the Spring Generator (7.23.0), not even for JsonNullable. It’s all handled by the ObjectMapper.

@gs-covariance can you share your openapi schema for the generated DTO

gs-covariance commented on Jul 24, 2026

@gs-covariance
Author

@MelleD As I said before, this happens on every optional non-nullable field

openapi: 3.1.0
info: { title: repro, version: 1.0.0 }
paths: {}
components:
  schemas:
    Example:
      type: object
      properties:
        a:
          type: string
        b:
          type: integer
        c:
          type: array
          items: { type: string }

MelleD commented on Jul 24, 2026

@MelleD
Contributor

@gs-covariance just want do double check if you have right format and etc. but then I will have the same issue when I upgrade

Picazsoo commented on Jul 24, 2026

@Picazsoo
Contributor

Hi @MelleD, I did some tests locally and I confirm that @JsonInclude(NON_ABSENT) is not necessary at all when the JsonNullableModule or JsonNullableJackson3Module are properly registered in the jsonMapper/objectMapper.

So I definitely concede that point - for JsonNullable<T> those @JsonInclude(NON_ABSENT) annotations are useless and just noise. The JsonNullable module's serializer takes precedence no matter what global inclusion is specified.

I'll remove the NON_ABSENT annotations from the templates.

I do want to keep the scope explicit, since these are two separable claims:

  • NON_ABSENT on JsonNullable<T> (the openApiNullable=true path) → redundant, dropping it. ✅ Conceded.
  • NON_NULL on optional non-nullable fields (the default openApiNullable=false path) → still needed. There's no wrapper type there — it's a plain T? = null - so no datatype module participates and inclusion falls back entirely to the global policy. Under ALWAYS (Jackson's baseline / Spring's effective default) that serializes "field": null for a field the schema declares non-nullable, which is spec-invalid output. So unlike NON_ABSENT, that one isn't noise.

Net plan: drop NON_ABSENT on JsonNullable fields, keep NON_NULL on optional non-nullable fields, and still expose the opt-out configOption for anyone who wants to own inclusion entirely at the mapper level. I'll wire this into the follow-up PR and tag you on it.

Picazsoo commented on Jul 24, 2026

@Picazsoo
Contributor

Revised plan (post-NON_ABSENT concession)

Following up on my last comment to fold the NON_ABSENT finding back into the overall design, so the earlier proposal and matrix don't mislead anyone reading this thread later.

What changed from the original proposal:

  • @JsonInclude(NON_ABSENT) on JsonNullable<T> fields is being dropped entirely. Verified locally: when JsonNullableModule / JsonNullableJackson3Module is registered, the module's serializer takes precedence over any global inclusion policy, so the annotation is pure noise. This removes the "one genuinely non-negotiable case" from my earlier comment. It turns out there wasn't one.
  • Because of that, generateJsonIncludeAnnotations=false now becomes a true, complete escape hatch: with it off, generated models carry no policy @JsonInclude at all, and inclusion is owned 100% by the global ObjectMapper. No JsonNullable carve-out anymore.

What stays the same:

  • NON_NULL on optional non-nullable fields is still emitted by default. There's no wrapper type on that path (T? = null / plain T), so no datatype module participates and inclusion falls back to the global policy. Under Jackson's ALWAYS baseline that serializes "field": null for a field the schema declares non-nullable, which is spec-invalid, so this one is not noise.
  • Both config options remain:
    • optionalNonNullPropertyJsonInclude (NON_NULL default / NON_EMPTY / NON_DEFAULT / NONE): policy for optional non-nullable fields; NONE emits nothing.
    • generateJsonIncludeAnnotations (default true): global on/off for all policy annotations.
  • Manual per-property vendor extension still always wins.

Updated summary matrix (no manual override, generateJsonIncludeAnnotations=true):

Property Nullable Kotlin (auto) Java (auto)
required non-nullable ALWAYS NON_NULL
required nullable ALWAYS ALWAYS
optional non-nullable via optionalNonNullPropertyJsonInclude (default NON_NULL) via optionalNonNullPropertyJsonInclude (default NON_NULL)
optional nullable (openApiNullable=true) (none, was NON_ABSENT, now dropped) (none, was NON_ABSENT, now dropped)

@gs-covariance, thanks for the minimal repro, that matches exactly what the NON_NULL-on-optional path produces, and it's the behavior these options are meant to let you control. @MelleD, with the NON_ABSENT removal, generateJsonIncludeAnnotations=false gives you the clean "let the ObjectMapper own everything" mode you were describing.

What do you think?

Thanks for your patience.

jorgerod commented on Jul 24, 2026

@jorgerod
Contributor

Context: impact at scale in a corporate framework

We maintain a corporate Java/Spring framework that wraps openapi-generator (custom generators extending SpringCodegen/JavaClientCodegen) and is used by hundreds of development teams. Every generator version bump propagates automatically to all services that regenerate their code at build time.

While evaluating the upgrade from 7.23.0 to 7.24.0, we compared the generated code of our integration modules between both versions: ~470 server DTOs gained ~1,550 new annotations (@JsonInclude(NON_NULL) on fields and @JsonSetter(nulls = Nulls.SKIP) on setters) introduced by #23993 and #24185. We have decided to stay on 7.23.0 until there is an upgrade path that does not change the serialization behavior of our services.

The problem, from the perspective of someone operating many services

The change is doubly silent:

  1. Responses (@JsonInclude(NON_NULL)): as already described in this issue, the field-level annotation takes precedence over the global ObjectMapper policy, and consumers that distinguish "field present with null" from "field absent" see a de facto contract change.
  2. Requests (@JsonSetter(nulls = Nulls.SKIP)): this is, for us, the most severe one and the least discussed in this thread. An explicit null in the request body is now silently ignored and the default value is kept. The semantics of PATCH-style operations change: {"field": null} used to set null; now it doesn't. It doesn't fail at compile time, at startup, or at runtime — it simply changes data. In a mass migration, this class of change is nearly impossible to detect until it produces a data incident.

Note that #23993 explicitly asked for java-spring feedback before merging ("It would be really good to get some java-spring feedback for the Nulls.SKIP for optional non-nullable"). This comment intends to be that feedback, with the use case of operating the change at scale.

Main request: make the 7.25.0 default preserve the 7.23.0 output

We propose that generateJsonIncludeAnnotations default to false, so that the default behavior on upgrade is that of 7.23.0, and the protection against emitting explicit null becomes opt-in.

We understand the correctness argument (under ALWAYS, an optional non-nullable field can serialize "field": null, which is spec-invalid). But that behavior has been the status quo for all generator users for years: fixing it by default turns a tooling upgrade into an unsolicited wire contract change. The spec-correctness fix is valuable — as a conscious user choice, not as a side effect of a version bump. The precedent in this very discussion points in that direction: NON_ABSENT was conceded as unnecessary after feedback; the principle "the default doesn't change the wire" is the generalization of that same logic.

Fallback requests (if the default stays true)

  1. Make generateJsonIncludeAnnotations=false also cover the @JsonSetter(nulls = Nulls.SKIP) introduced by [kotlin-spring, java-spring] - gate @JsonSetter on openApiNullable for optional non-nullable fields #23993. The plan described in this thread only mentions the @JsonInclude annotations; if the flag does not also disable the @JsonSetter, the escape hatch is incomplete: the deserialization semantics change (for us the most dangerous one) would remain without an opt-out. Alternatively, a dedicated flag for it.
  2. Highlight the behavior change prominently in the release notes of 7.24.x/7.25.0 as an explicit behavior change (response serialization + null-handling semantics in deserialization), with the restoring flag documented. The current 7.24.0 highlights do not make it possible to anticipate the impact without diffing generated code.

Thank you for the transparency with which this issue is being handled — the proposed flag plan is already a big improvement; these requests aim to make the upgrade path safe also for those walking it with hundreds of services at once.

Picazsoo commented on Jul 24, 2026

@Picazsoo
Contributor

Hi @jorgerod, first let me apologize for any inconvenience caused, and thanks for the feedback I specifically asked for.

On the default for generateJsonIncludeAnnotations: that's fair and up for discussion, I don't mind either option. Whatever the default, it needs a loud, clear mention in the release notes, and possibly a clear log line during generation so nobody gets surprised on upgrade.

On wholesale dropping of the @JsonSetter annotations: I'd honestly prefer a separate boolean configOption for that, rather than overloading generateJsonIncludeAnnotations, so the serialization opt-out and the deserialization opt-out stay independent.

Now to the Nulls.SKIP part specifically, because I think the baseline it's compared against is worth examining.

Scoping note first: AFAIK @JsonSetter(nulls = Nulls.SKIP) is only ever emitted on optional non-nullable fields (!required && !isNullable). Never on required fields, never on nullable ones. So the only affected fields are ones the schema says cannot hold null, which means an incoming {"field": null} there is already out-of-contract input.

That reframes the comparison. The real question isn't "should an explicit null set null?" (for a non-nullable field it arguably never should), but what to do with an illegal null:

  • Before (no annotation, Jackson's default Nulls.SET): the null is assigned. The non-nullable field ends up holding null, a spec-invalid state accepted silently. To me that's the worst option: it doesn't reject the null, doesn't ignore it, it commits it.
  • Now (Nulls.SKIP): the illegal null is dropped and the field keeps its default. Still silent, but the field never enters a state the schema forbids.

So I fully agree the silence of the change (and the lack of a prominent release-note signal for a fleet-wide upgrade) is a real problem worth fixing. But I don't think the old behavior was a "correct" baseline we regressed from. It was itself silently violating the non-nullable contract.

On the PATCH example specifically ({"field": null} used to set null, now it doesn't): I want to be precise here, because two conditions are mutually exclusive. {"field": null} meaning "set this to null" is only a valid expectation for a nullable field. A nullable field with openApiNullable=true is generated as JsonNullable<T> and gets no @JsonSetter(nulls = SKIP) at all, so null-setting keeps working there. Nulls.SKIP is only ever added to non-nullable fields, where an explicit null was never a legal value to begin with. So there is no field on which "PATCH null-setting was valid" and "Nulls.SKIP now silences it" are both true. Also worth stressing: @JsonSetter only affects deserialization of request bodies. It has no effect on response serialization, which is the separate @JsonInclude concern.

If it were up to me, for these optional non-nullable fields I'd lean toward Nulls.FAIL: loudly reject the illegal null and enforce the contract on both sides, which is exactly the "louder failure beats silent data change" principle you invoke elsewhere. For genuinely nullable fields where explicit null is meaningful, openApiNullable=true with JsonNullable<T> is the right tool, since it preserves the absent-vs-null distinction.

Looking forward to your reply!

jorgerod commented on Jul 24, 2026

@jorgerod
Contributor

Hi @Picazsoo, thanks for the detailed response — and point conceded on the PATCH example.

1. On the scoping of Nulls.SKIP: you're right

Your scoping analysis is correct and I withdraw the example as I framed it: on a field declared nullable, null-setting keeps working (via JsonNullable<T>), and Nulls.SKIP only applies to fields where an explicit null was never legal input to begin with. The previous baseline (Nulls.SET assigning null to a non-nullable field) wasn't a "correct" behavior we regressed from either — it was a silent contract violation in the other direction.

2. The operational nuance I stand by

That said, the risk that concerns us at fleet scale doesn't disappear, it just changes nature: imperfect specs. In a large service base there is a real population of fields that are de facto nullable but were never declared nullable: true, with clients sending null and server code that has been handling it for years. That traffic is out-of-contract — no argument there — but it is operational today. With Nulls.SKIP, those flows change behavior without an error at any layer: the proper fix is fixing the spec, but the window between "I bump the generator" and "I discover which specs were wrong" is exactly where data incidents happen. Hence our insistence on opt-outs and conservative defaults: we're not defending the old behavior as correct, we're defending that moving from one to the other should be a conscious, per-service decision.

By the same logic: if Nulls.FAIL eventually lands for these fields (and we agree it's the most contract-honest behavior), we'd ask for it to be opt-in — it would turn that same tolerated traffic into deserialization errors across an entire fleet at once.

3. Separate flag for @JsonSetter: agreed

A dedicated boolean for the deserialization opt-out works for us — keeping the serialization axis (@JsonInclude) and the deserialization axis (@JsonSetter) independent is cleaner. With both flags available, our upgrade path is clean: we pin both in our corporate generator and each team decides when to adopt the new behaviors.

4. On the default for generateJsonIncludeAnnotations

Since you're leaving it open: our vote is default false (= 7.23.0 output on upgrade), with the protection as opt-in. The reasoning is the same as before: for an individual user the flag is a detail; for a fleet upgrade, the default is the behavior. And with NON_ABSENT already dropped as redundant, the cost of defaulting to false is only not protecting by default against the spec-invalid "field": null — which is the status quo everyone has today.

In any case, the prominent release-notes mention and the log line during generation sound like excellent ideas regardless of which default is chosen — the log line in particular helps exactly where release notes don't reach (transitive upgrades via frameworks/BOMs like ours).

Thanks again for how you're handling this.

Picazsoo commented on Jul 24, 2026

@Picazsoo
Contributor

Hi @jorgerod, your point of view makes a lot of sense. On the other hand it is strange to default to generating incorrect and misleading models that serialize and deserialize incorrectly. Imagine new adopters of the tooling: they generate their models, never think of it again, accidentally rely on the incorrect modelling, and later end up stuck in exactly the situation you're in now, except they never got a signal that a choice was being made for them.

Building on this: maybe the cleanest resolution is to default to the weaker/upgrade-safe contract, but log loudly that it is weak and can (and generally should) be tightened. The only way to mute the log is to set the flag explicitly, either to the stricter policy, or explicitly to the weak one to affirm "yes, I want this."

That gives us:

  • flag unset → weak behavior + warning (nobody's build breaks, no wire change on upgrade, but the weakness is never silent),
  • explicitly weak → weak behavior, no warning (muted by conscious choice),
  • explicitly strict → correct behavior, no warning.

So the default preserves 7.23.0 output for you and the fleet, while new adopters can't unknowingly marry the weaker contract forever. They get a persistent, actionable nudge until they make a real decision. Silence becomes something you opt into, never something you inherit.

And this works per axis: safe-but-noisy default on both @JsonInclude and the @JsonSetter/Nulls flag, which keeps the dangerous deserialization axis conservative-by-default too. It's essentially your generation-time log-line idea, just escalated to fire specifically when the flag is left unset.

Does this make sense to you?

MelleD commented on Jul 24, 2026

@MelleD
Contributor

My assumption was that all relevant Jackson modules are properly registered everywhere, for example JsonNullableModule, the JDK modules, etc. The ObjectMapper should of course also be configured consistently across the whole application landscape; otherwise things become very hard to reason about.

So, in summary, for the Spring generator I do not think I need any @JsonInclude annotations at all. That said, I also do not have all theoretical cases in practice — out of the four possible combinations, only three are actually relevant in my setup.

Picazsoo commented on Jul 24, 2026

@Picazsoo
Contributor

My assumption was that all relevant Jackson modules are properly registered everywhere, for example JsonNullableModule, the JDK modules, etc. The ObjectMapper should of course also be configured consistently across the whole application landscape; otherwise things become very hard to reason about.

👍

So I gather you are on openApiNullable=true with a global mapper set to something stricter than ALWAYS (that's the only way you get zero annotations and still-correct output).

But that only works because your schema doesn't hit both conflicting cases at once. A single global inclusion policy can't satisfy both:

  • optional + non-nullable wants the field omitted (no null). Correct under global NON_NULL/NON_EMPTY, but emits the spec-invalid "field": null under ALWAYS.
  • required + nullable wants "field": null on the wire. Correct under ALWAYS, but silently dropped under NON_NULL/NON_EMPTY, breaking required.

So tightening the global default fixes the first and breaks the second. There's no single global value that's right for both. That's precisely why the per-field @JsonInclude exists: each field carries the policy it needs (NON_NULL on optional non-nullable, ALWAYS on required nullable) independent of the one global setting.

Your "3 of 4 combinations" is the reason you don't feel it: as soon as a schema has both an optional non-nullable field and a required nullable one, the global-only approach breaks one of them. That's why the annotation stays generatable, with generateJsonIncludeAnnotations=false for setups like yours that stay within the safe subset.

MelleD commented on Jul 24, 2026

@MelleD
Contributor

So I gather you are on openApiNullable=true with a global mapper set to something stricter than ALWAYS (that's the only way you get zero annotations and still-correct output).

Correct non empty.

I do not have both cases:
Currently is:
optional empty is absent/blank/null
required is not null + min size 1

Picazsoo commented on Jul 29, 2026

@Picazsoo
Contributor

Hi, PR with the agreed-upon changes is here: #24428

Picazsoo commented on Aug 26, 2026

@Picazsoo
Contributor

Hello @MelleD , @jorgerod , @gs-covariance, the new version 7.25.0 has been released with the fix in place. Does it solve the issues for you? It is pretty configurable, so it should be able to satisfy all cases. But it would be great to have some concrete confirmation from you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions