Annotation Interface WithheldFromApi


@Target({METHOD,FIELD}) @Retention(RUNTIME) public @interface WithheldFromApi
Withhold a property from the RESTful API, and say why.

This is JsonIgnore underneath, so an annotated field or getter is absent from the serialized response — and, because swagger-core introspects through Jackson, absent from the generated OpenAPI document too. It is a serialization control, not a documentation hint.

Why the reason is required

This replaces @GemmaWebOnly, which asserted "exclusively used for Gemma Web". Gemma Web was deleted in bb154eee88, which made that sentence false at all 79 of its call sites and left exactly one argument available to anyone reading it: Gemma Web is gone, so this hiding is vestigial, so remove it.

That argument is correct for most of those members. Applied to ExpressionExperimentValueObject.getCurrentUserIsOwner() it would publish per-caller authorization state onto a response carrying @CacheControl(maxAge = 1200). The old marker gave you no way to tell the two apart, so value() has no default: a suppression that does not state its reason is the thing that created this problem, and a marker that cannot be applied without one cannot recreate it.

WithheldFromApiInventoryTest pins every application of this annotation, so adding, removing or re-reasoning one is a deliberate, reviewed edit rather than a silent API change. It also asserts that nothing marked WithheldFromApi.Reason.CALLER_IDENTITY or WithheldFromApi.Reason.DISCLOSURE can reach the wire, and that the WithheldFromApi.Reason.UNTRIAGED population only ever shrinks.

@WithheldFromApi(value = Reason.CALLER_IDENTITY,
        comment = "per-principal ownership on a response cached by URL")
public boolean getCurrentUserIsOwner() { ... }
The bucketing that produced the initial reasons is in docs/recce/GEMMA_WEB_ONLY_AUDIT.md.

There was briefly a PUBLIC_PROJECTION_EXISTS reason, for a member whose safe subset a parallel value object published. It was removed: its only claimed instance, PublicGeeqValueObject, turned out to serialize a payload identical to the VO it was supposedly projecting, and once the "unfiltered internal form" half of its meaning moved to WithheldFromApi.Reason.INTERNAL_ONLY, what remained said only "the data is published elsewhere" — which is WithheldFromApi.Reason.REDUNDANT.

Author:
paul
See Also:
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static enum 
     
  • Required Element Summary

    Required Elements
    Modifier and Type
    Required Element
    Description
    Why this member is withheld.
  • Optional Element Summary

    Optional Elements
    Modifier and Type
    Optional Element
    Description
    The specific hazard, the projection to use instead, or what to check before exposing this.
  • Element Details

    • value

      Why this member is withheld. Required — see the type javadoc.
    • comment

      String comment
      The specific hazard, the projection to use instead, or what to check before exposing this.

      Strongly encouraged on WithheldFromApi.Reason.UNTRIAGED, where it is the note the next person needs.

      Default:
      ""