Skip to content

Commit

Permalink
[JAVA] fix: oneOf generates incorrect model for primitive types (#16834)
Browse files Browse the repository at this point in the history
* generate samples

* try fix

* add new sample for fixed case

* also improve native library

Other libraries don't need fixes.

* add oneOf_twoPrimitives.yaml

* generate samples

* resolve comment
  • Loading branch information
martin-mfg authored Oct 16, 2023
1 parent 438bf25 commit b6db4f7
Show file tree
Hide file tree
Showing 51 changed files with 4,996 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .github/workflows/samples-java-client-jdk11.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ on:
- samples/openapi3/client/petstore/java/jersey2-java8-swagger1/**
- samples/openapi3/client/petstore/java/jersey2-java8-swagger2/**
- samples/openapi3/client/petstore/java/native**
- samples/client/others/java/okhttp-gson-oneOf/**
- samples/client/others/java/resttemplate-useAbstractionForFiles/**
- samples/client/others/java/webclient-useAbstractionForFiles/**
pull_request:
Expand All @@ -21,6 +22,7 @@ on:
- samples/openapi3/client/petstore/java/jersey2-java8-swagger1/**
- samples/openapi3/client/petstore/java/jersey2-java8-swagger2/**
- samples/openapi3/client/petstore/java/native**
- samples/client/others/java/okhttp-gson-oneOf/**
- samples/client/others/java/resttemplate-useAbstractionForFiles/**
- samples/client/others/java/webclient-useAbstractionForFiles/**
jobs:
Expand Down Expand Up @@ -65,6 +67,7 @@ jobs:
- samples/client/petstore/java/okhttp-gson-swagger2/
- samples/client/petstore/java/resttemplate-swagger2/
- samples/openapi3/client/petstore/java/jersey2-java8-swagger2/
- samples/client/others/java/okhttp-gson-oneOf/
- samples/client/others/java/resttemplate-useAbstractionForFiles/
- samples/client/others/java/webclient-useAbstractionForFiles/
steps:
Expand Down
7 changes: 7 additions & 0 deletions bin/configs/java-okhttp-gson-oneOf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
generatorName: java
outputDir: samples/client/others/java/okhttp-gson-oneOf
library: okhttp-gson
inputSpec: modules/openapi-generator/src/test/resources/3_0/oneOf_twoPrimitives.yaml
templateDir: modules/openapi-generator/src/main/resources/Java
additionalProperties:
hideGenerationTimestamp: "true"
Original file line number Diff line number Diff line change
Expand Up @@ -7248,7 +7248,7 @@ protected void addBodyModelSchema(CodegenParameter codegenParameter, String name
codegenParameter.description = codegenModelDescription;
imports.add(codegenParameter.baseType);

if (codegenProperty.complexType != null) {
if (codegenProperty.complexType != null && codegenProperty.getComposedSchemas() == null) {
imports.add(codegenProperty.complexType);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
StringJoiner joiner = new StringJoiner("&");

{{#composedSchemas.oneOf}}
{{^vendorExtensions.x-duplicated-data-type}}
if (getActualInstance() instanceof {{{dataType}}}) {
{{#isArray}}
{{#items.isPrimitiveType}}
Expand Down Expand Up @@ -352,6 +353,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
{{/isArray}}
return joiner.toString();
}
{{/vendorExtensions.x-duplicated-data-type}}
{{/composedSchemas.oneOf}}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
StringJoiner joiner = new StringJoiner("&");

{{#composedSchemas.oneOf}}
{{^vendorExtensions.x-duplicated-data-type}}
if (getActualInstance() instanceof {{{dataType}}}) {
{{#isArray}}
{{#items.isPrimitiveType}}
Expand Down Expand Up @@ -385,6 +386,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
{{/isArray}}
return joiner.toString();
}
{{/vendorExtensions.x-duplicated-data-type}}
{{/composedSchemas.oneOf}}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
{{#composedSchemas}}
{{#anyOf}}
{{^isArray}}
{{^vendorExtensions.x-duplicated-data-type}}
final TypeAdapter<{{{dataType}}}> adapter{{{dataType}}} = gson.getDelegateAdapter(this, TypeToken.get({{{dataType}}}.class));
{{/vendorExtensions.x-duplicated-data-type}}
{{/isArray}}
{{#isArray}}

Expand All @@ -68,6 +70,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im

{{#composedSchemas}}
{{#anyOf}}
{{^vendorExtensions.x-duplicated-data-type}}
// check if the actual instance is of the type `{{{dataType}}}`
if (value.getActualInstance() instanceof {{#isArray}}List<?>{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}) {
{{#isPrimitiveType}}
Expand All @@ -91,6 +94,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
{{/isPrimitiveType}}
{{/isArray}}
}
{{/vendorExtensions.x-duplicated-data-type}}
{{/anyOf}}
{{/composedSchemas}}
throw new IOException("Failed to serialize as the type doesn't match anyOf schemae: {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}");
Expand All @@ -106,6 +110,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
{{#composedSchemas}}
{{#anyOf}}
{{^vendorExtensions.x-duplicated-data-type}}
{{^hasVars}}
// deserialize {{{dataType}}}
try {
Expand Down Expand Up @@ -184,6 +189,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
log.log(Level.FINER, "Input data does not match schema '{{{.}}}'", e);
}
{{/hasVars}}
{{/vendorExtensions.x-duplicated-data-type}}
{{/anyOf}}
{{/composedSchemas}}

Expand All @@ -210,7 +216,9 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
static {
{{#composedSchemas}}
{{#anyOf}}
{{^vendorExtensions.x-duplicated-data-type}}
schemas.put("{{{dataType}}}", {{{baseType}}}.class);
{{/vendorExtensions.x-duplicated-data-type}}
{{/anyOf}}
{{/composedSchemas}}
}
Expand Down Expand Up @@ -238,6 +246,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
{{/isNullable}}
{{#composedSchemas}}
{{#anyOf}}
{{^vendorExtensions.x-duplicated-data-type}}
if (instance instanceof {{#isArray}}List<?>{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}) {
{{#isArray}}
List<?> list = (List<?>) instance;
Expand All @@ -252,6 +261,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
{{/isArray}}
}

{{/vendorExtensions.x-duplicated-data-type}}
{{/anyOf}}
{{/composedSchemas}}
throw new RuntimeException("Invalid instance type. Must be {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}");
Expand All @@ -270,6 +280,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im

{{#composedSchemas}}
{{#anyOf}}
{{^vendorExtensions.x-duplicated-data-type}}
/**
* Get the actual instance of `{{{dataType}}}`. If the actual instance is not `{{{dataType}}}`,
* the ClassCastException will be thrown.
Expand All @@ -280,6 +291,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
public {{{dataType}}} get{{#isArray}}{{complexType}}List{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}() throws ClassCastException {
return ({{{dataType}}})super.getActualInstance();
}
{{/vendorExtensions.x-duplicated-data-type}}
{{/anyOf}}
{{/composedSchemas}}

Expand All @@ -294,6 +306,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
ArrayList<String> errorMessages = new ArrayList<>();
{{#composedSchemas}}
{{#anyOf}}
{{^vendorExtensions.x-duplicated-data-type}}
// validate the json string with {{{dataType}}}
try {
{{^hasVars}}
Expand Down Expand Up @@ -350,6 +363,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
errorMessages.add(String.format("Deserialization for {{{dataType}}} failed with `%s`.", e.getMessage()));
// continue to the next one
}
{{/vendorExtensions.x-duplicated-data-type}}
{{/anyOf}}
{{/composedSchemas}}
throw new IOException(String.format("The JSON string is invalid for {{classname}} with anyOf schemas: {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}. no class match the result, expected at least 1. Detailed failure message for anyOf schemas: %s. JSON: %s", errorMessages, jsonElement.toString()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
{{#composedSchemas}}
{{#oneOf}}
{{^isArray}}
{{^vendorExtensions.x-duplicated-data-type}}
final TypeAdapter<{{{dataType}}}> adapter{{{dataType}}} = gson.getDelegateAdapter(this, TypeToken.get({{{dataType}}}.class));
{{/vendorExtensions.x-duplicated-data-type}}
{{/isArray}}
{{#isArray}}

Expand All @@ -68,6 +70,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im

{{#composedSchemas}}
{{#oneOf}}
{{^vendorExtensions.x-duplicated-data-type}}
// check if the actual instance is of the type `{{{dataType}}}`
if (value.getActualInstance() instanceof {{#isArray}}List<?>{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}) {
{{#isPrimitiveType}}
Expand All @@ -91,6 +94,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
{{/isPrimitiveType}}
{{/isArray}}
}
{{/vendorExtensions.x-duplicated-data-type}}
{{/oneOf}}
{{/composedSchemas}}
throw new IOException("Failed to serialize as the type doesn't match oneOf schemas: {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}");
Expand Down Expand Up @@ -131,6 +135,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im

{{#composedSchemas}}
{{#oneOf}}
{{^vendorExtensions.x-duplicated-data-type}}
{{^hasVars}}
// deserialize {{{dataType}}}
try {
Expand Down Expand Up @@ -206,6 +211,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
log.log(Level.FINER, "Input data does not match schema '{{{.}}}'", e);
}
{{/hasVars}}
{{/vendorExtensions.x-duplicated-data-type}}
{{/oneOf}}
{{/composedSchemas}}

Expand Down Expand Up @@ -238,7 +244,9 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
static {
{{#composedSchemas}}
{{#oneOf}}
{{^vendorExtensions.x-duplicated-data-type}}
schemas.put("{{{dataType}}}", {{{baseType}}}.class);
{{/vendorExtensions.x-duplicated-data-type}}
{{/oneOf}}
{{/composedSchemas}}
}
Expand Down Expand Up @@ -266,6 +274,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
{{/isNullable}}
{{#composedSchemas}}
{{#oneOf}}
{{^vendorExtensions.x-duplicated-data-type}}
if (instance instanceof {{#isArray}}List<?>{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}) {
{{#isArray}}
List<?> list = (List<?>) instance;
Expand All @@ -280,6 +289,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
{{/isArray}}
}

{{/vendorExtensions.x-duplicated-data-type}}
{{/oneOf}}
{{/composedSchemas}}
throw new RuntimeException("Invalid instance type. Must be {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}");
Expand All @@ -298,6 +308,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im

{{#composedSchemas}}
{{#oneOf}}
{{^vendorExtensions.x-duplicated-data-type}}
/**
* Get the actual instance of `{{{dataType}}}`. If the actual instance is not `{{{dataType}}}`,
* the ClassCastException will be thrown.
Expand All @@ -308,6 +319,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
public {{{dataType}}} get{{#isArray}}{{complexType}}List{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}() throws ClassCastException {
return ({{{dataType}}})super.getActualInstance();
}
{{/vendorExtensions.x-duplicated-data-type}}
{{/oneOf}}
{{/composedSchemas}}

Expand All @@ -323,6 +335,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
ArrayList<String> errorMessages = new ArrayList<>();
{{#composedSchemas}}
{{#oneOf}}
{{^vendorExtensions.x-duplicated-data-type}}
// validate the json string with {{{dataType}}}
try {
{{^hasVars}}
Expand Down Expand Up @@ -379,6 +392,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
errorMessages.add(String.format("Deserialization for {{{dataType}}} failed with `%s`.", e.getMessage()));
// continue to the next one
}
{{/vendorExtensions.x-duplicated-data-type}}
{{/oneOf}}
{{/composedSchemas}}
if (validCount != 1) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
openapi: 3.0.3
info:
title: oneOf two primitives
description: oneOf with two entries of type string, see https://github.com/OpenAPITools/openapi-generator/issues/10450
version: 1.0.0
paths:
/myExample:
post:
requestBody:
content:
application/json:
schema:
oneOf:
- type: string
format: ipv4
- type: string
format: ipv6
responses:
200:
description: OK
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
#
# This file is auto-generated by OpenAPI Generator (https://openapi-generator.tech)

name: Java CI with Maven

on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]

jobs:
build:
name: Build oneOf two primitives
runs-on: ubuntu-latest
strategy:
matrix:
java: [ '8' ]
steps:
- uses: actions/checkout@v2
- name: Set up JDK
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java }}
distribution: 'temurin'
cache: maven
- name: Build with Maven
run: mvn -B package --no-transfer-progress --file pom.xml
21 changes: 21 additions & 0 deletions samples/client/others/java/okhttp-gson-oneOf/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
*.class

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear

# exclude jar for gradle wrapper
!gradle/wrapper/*.jar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

# build files
**/target
target
.gradle
build
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator

# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.

# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs

# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux

# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux

# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md
Loading

0 comments on commit b6db4f7

Please sign in to comment.