OpenAPITools / OpenAPITools/openapi-generator

[REQ] spring generator: add option to generate Visitor

Open
#11,231 2 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Enhancement: Feature
Dominant language
Java
Stars
26.8k
Forks
7.7k
PR merge metrics
PR metrics pending

Description

Is your feature request related to a problem? Please describe.

Parsing class hierarchies generated from OpenAPI results in ugly boilerplate code in Java.

For example, if we have an endpoint that returns an Animal, we may need to figure out what kind of subclass is returned.

image

We end up with code like:

if (animal instanceof Duck duck) {
  …
} else if (animal instanceof Fish fish) {
  …
} else if (animal instanceof Zebra zebra) {
  …
}

This doesn't scale properly as we end up with a 300 line megamoth, and is also prone to errors if one is not cautious (if we add a new animal type, best case scenario is to detect it on runtime with a throw new NewAnimalDetectedException() as a catch-all at the end).

Describe the solution you'd like

I'd like a more OOP solution, and my suggestion is to use the slightly-criticized Visitor pattern:

public interface AnimalVisitor<T> {
  T visit(Duck duck);
  T visit(Fish fish);
  T visit(Zebra zebra);
}

This should be implemented by the OpenAPI Generator, as it requires modification of the classes it generates:

public class Duck || Fish || Zebra {
  …
  @Override
  public <T> T accept(AnimalVisitor<T> visitor) { return visitor.visit(this); }
}
Issues

To the best of my knowledge, OpenAPI does not disallow instantiation of superclass. Visitor requires the superclass to not be allowed. Is this part of the spec, planned to be part of the spec, or…?

Describe alternatives you've considered

Usage of sealed types instead of Visitor pattern to avoid the ugly indirections, but falling back to having megamoths.

sealed interface Animal permits Duck, Fish, Zebra { }

  private void playSoundOf(Animal animal) {
    switch (animal) {
      case Duck body -> quackQuack();
      case Fish car_ -> blurbBlurb();
      case Zebra engine -> zebraSounds();
    }
  }

No other alternatives AFAIK, but as I'm not the most seasoned Java programmer, feel free to prove me wrong! :)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating the spring generator's model templates and option definitions, then inspect how inheritance and generated Java models are handled. Compare the requested Visitor pattern with existing polymorphism behavior and clarify the superclass-instantiation constraint. Done means the generator has a defined Visitor option and its expected generated output is covered by appropriate tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
api, backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.