Skip to content

Conversation

@B4ckslash
Copy link
Contributor

@B4ckslash B4ckslash commented Mar 6, 2024

Description

Changes

As has already been described in #17745, the code generated for Java with Jersey2 for a oneOf-model can be invalid if one of the possible types is of array type. This is presumably due to the fact that #13897 only fixed the templates for okhttp-gson, but not other serialization libraries. This PR updates the oneOf_model template for jersey2 as well as add a sample which generates a mixed oneOf model using jersey2 so as to catch regressions on this in future.

Beyond that, I've added a mustache lambda to AbstractJavaCodegen which replaces angle brackets, spaces and commas with nothing. This is done so that the data type of any parametrized type may be used in identifiers (e.g. method names of getters) to prevent clashing method signatures. This example used to fail compilation due to clashing erasures:

public List<String> getList() {...}
public List<List<Integer>> getList() {...}

whereas now, one can generate something like:

public List<String> getListString() {...}
public List<List<Integer>> getListListInteger {...}

This also has the added benefit of automatically changing the method name should the return type ever change, forcing a user to think about handling the changed datatype, which would be impossible if it were a simple public List<?> getList().
Another benefit is the ability to use the actual generic type that the user can expect instead of just giving them a wildcarded List.

Possible future work

PR checklist

  • Read the contribution guidelines.
  • Pull Request title clearly describes the work in the pull request and Pull Request description provides details about how to validate the work. Missing information here may result in delayed response from the community.
  • Run the following to build the project and update samples:
    ./mvnw clean package 
    ./bin/generate-samples.sh ./bin/configs/*.yaml
    ./bin/utils/export_docs_generators.sh
    
    (For Windows users, please run the script in Git BASH)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • File the PR against the correct branch: master (upcoming 7.1.0 minor release - breaking changes with fallbacks), 8.0.x (breaking changes without fallbacks)
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

@bbdouglas @sreeshas @jfiala @lukoyanov @cbornet @jeff9finger @karismann @Zomzog @lwlee2608 @martin-mfg

@wing328
Copy link
Member

wing328 commented Mar 6, 2024

thanks for the PR. the CI tests failed: https://circleci.com/gh/OpenAPITools/openapi-generator/90090

can you please take a look when you've time?

@B4ckslash
Copy link
Contributor Author

B4ckslash commented Mar 7, 2024

@wing328 I think the CI ought to work now. However, looking through the templates for other Java libraries (esp. Gson), I think I may have found a better way to go about this fix with only adjusting the templates.
In any case, I will add a sample and/or test case to properly test this behavior before re-doing the fix.
I will mark the PR as draft for the time being.

@B4ckslash B4ckslash marked this pull request as draft March 7, 2024 09:31
@B4ckslash B4ckslash marked this pull request as ready for review March 7, 2024 14:03
@B4ckslash
Copy link
Contributor Author

@wing328 ok I'm done. Perhaps someone from the Java experts can look over this now.

@wing328
Copy link
Member

wing328 commented Mar 12, 2024

when you've time, can you please PM me via Slack when you've time?

I may have other ways to handle array in oneOf/anyOf schema bette.r

@B4ckslash
Copy link
Contributor Author

Yeah I can do that, if you tell me where and how to find you. I've not used slack for a long while.

@wing328
Copy link
Member

wing328 commented Mar 16, 2024

Changes:
* Change jersey2/oneof_model template to use composed schema data
* Change adding of imports in AbstractJavaCodegen to use composed schema data
* Add escapedDataType property to CodegenProperty so that the data type
  may be part of identifiers (e.g. in getters)
* Update samples
@B4ckslash
Copy link
Contributor Author

Alright so as per our Slack chat, I've changed the following (and updated the original description where applicable):

  • Primitives are handled more explicitly in the template, using the appropriate flags in the corresponding property. This blows up the template a bit, but reduces generated code a fair amount (e.g. completely removing the runtime class check when the property is not primitive)
  • The pre-escaped data type got replaced with a mustache lambda which strips angle brackets, commas, and spaces

Assuming the tests pass, this PR is finally ready to be merged 🥳

@wing328 wing328 merged commit 807aa5d into OpenAPITools:master Mar 30, 2024
return openapiGeneratorIgnoreList;
}

@Override
Copy link
Member

Choose a reason for hiding this comment

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

can you describe what isTypeErasedGenerics does with a line or two and I'll add a docstring to the method below in my upcoming PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry for the late reply. isTypeErasedGenerics is meant to tell the code generator whether the target language is erasing the generic parameter(s) at runtime, which has implications for handling the possible types in things like the constructor or instanceof checks. As an example, if the language has type erased generics, the compiler throws an error when you do something like

public Constructor(final List<String> args) {...}

public Constructor(final List<Integer> args) {...}

because both the signatures erase to the same signature Constructor(final List args) which is not allowed. Therefore you need a way to check whether the code generation can include the full parametrized type List<String> and do so potentially multiple times, or if it has to only use it once as the base type List.

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes I use that as well, but I have to determine on the codegen side whether that is even applicable. In languages that do not erase their generics, List<String> and List<Integer> are different data types, so in those languages using x-duplicated-data-type makes no sense. Depending on whether isTypeErasedGenerics is true, I set the x-duplicated-data-type flag for types affected by type erasure (if there are multiple variants of it).

@wing328
Copy link
Member

wing328 commented Apr 3, 2024

FYI. I've filed #18281 to sync the templates between jersey2 and jersey3

@wing328
Copy link
Member

wing328 commented Apr 3, 2024

when you've time, I wonder if you can you also update model_anyof template with the fix 🙏

@B4ckslash
Copy link
Contributor Author

I can have a look at it in a few days time I'm sure.

@B4ckslash B4ckslash deleted the javaOneOfList branch April 10, 2024 08:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants