swagger-api / swagger-api/swagger-codegen
[JAVA + okhttp] additionalProperties of type array not properly handled
Nobody has claimed this yet.
- Dominant language
- Mustache
- Stars
- 17.8k
- Forks
- 6k
- PR merge metrics
- No merged PRs in 30d
Description
Description
An additionalProperties of type array is not properly handled by the JavaClientCodegen with okhttp + GSON. See this example:
swagger: '2.0'
info:
version: 0.0.0
title: Foo
paths:
/foo1:
get:
responses:
200:
description: Foo
schema:
type: object
additionalProperties:
type: array
items:
$ref: '#/definitions/Foo'
definitions:
Foo:
type: object
properties:
foo:
type: string
This causes the code generator to produce the following class which has no additional field:
public class FooResponse extends HashMap<String, List> {
Note that the type of values in the hashmap is a List where it should have been a List<Foo>. Because of that, GSON doesn't deserialise the values to Foo objects. Instead, it gives just a LinkedHashMap<String, Object>.
If I modify the spec above and create a wrapper definition such as:
swagger: '2.0'
info:
version: 0.0.0
title: Foo
paths:
/foo2:
get:
responses:
200:
description: Foo
schema:
$ref: '#/definitions/FooResponse'
definitions:
Foo:
type: object
properties:
foo:
type: string
FooResponse:
type: object
additionalProperties:
type: array
items:
$ref: '#/definitions/Foo'
The generated DefaultApi class now lacks the import of Foo:
package io.swagger.client.api;
import io.swagger.client.ApiCallback;
import io.swagger.client.ApiClient;
import io.swagger.client.ApiException;
import io.swagger.client.ApiResponse;
import io.swagger.client.Configuration;
import io.swagger.client.Pair;
import io.swagger.client.ProgressRequestBody;
import io.swagger.client.ProgressResponseBody;
import com.google.gson.reflect.TypeToken;
import java.io.IOException;
import io.swagger.client.model.FooResponse;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DefaultApi {
// omitted
/**
*
*
* @return Map<String, List<Foo>>
* @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body
*/
public Map<String, List<Foo>> foo1Get() throws ApiException {
ApiResponse<Map<String, List<Foo>>> resp = foo1GetWithHttpInfo();
return resp.getData();
}
// omitted
}
Swagger-codegen version
2.4.5 (latest)
Swagger declaration file content or url
See above.
Command line used for generation
Copy the YAML specs above and paste on https://editor.swagger.io . Then go "Generate Client" > "Java". This is going to produce a Java client that uses the OkHTTP and GSON libraries.
Steps to reproduce
Explained above
Related issues/PRs
Not quite sure if this one is related: https://github.com/swagger-api/swagger-codegen/issues/6884
Suggest a fix/enhancement
Adding import {{modelPackage}}.*; to Java/libraries/okhttp-gson/api.mustache "fixes" the problem with the import.
I managed to get FooResponse to be generated as a HashMap<String, ArrayList<Foo>> by making the following change (hack):
diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java
index 096926470..e43fd30ec 100644
--- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java
+++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java
@@ -994,8 +994,15 @@ public class DefaultCodegen {
LOGGER.error("No Type defined for Additional Property " + additionalProperties2 + "\n" //
+ "\tIn Property: " + p);
}
- String inner = getSwaggerType(additionalProperties2);
- return instantiationTypes.get("map") + "<String, " + inner + ">";
+
+ String additionalPropInstType = toInstantiationType(additionalProperties2);
+
+ if (additionalPropInstType != null) {
+ return instantiationTypes.get("map") + "<String, " + additionalPropInstType + ">";
+ } else {
+ String inner = getSwaggerType(additionalProperties2);
+ return instantiationTypes.get("map") + "<String, " + inner + ">";
+ }
} else if (p instanceof ArrayProperty) {
ArrayProperty ap = (ArrayProperty) p;
String inner = getSwaggerType(ap.getItems());
All tests pass with both changes, but given that I'm not familiar with the codebase I don't feel confident to open a PR for this.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java and the Java/libraries/okhttp-gson/api.mustache template, then run the supplied Swagger specs through Java okhttp-gson generation. Done means array-valued additionalProperties preserve the Foo generic type and generated APIs include the required model import.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100