Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Java][client] make it possible to send explicit nulls for nullable fields #3474

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,12 @@
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson-version}</version>
</dependency>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>${jackson-databind-nullable-version}</version>
</dependency>

<!-- Joda time: if you use it -->
<dependency>
Expand All @@ -146,6 +151,7 @@
<swagger-annotations-version>1.5.8</swagger-annotations-version>
<jersey-version>2.27</jersey-version>
<jackson-version>2.8.9</jackson-version>
<jackson-databind-nullable-version>0.2.0</jackson-databind-nullable-version>
<jodatime-version>2.7</jodatime-version>
<maven-plugin-version>1.0.0</maven-plugin-version>
<junit-version>4.8.1</junit-version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,12 @@
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson-version}</version>
</dependency>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>${jackson-databind-nullable-version}</version>
</dependency>

<!-- Joda time: if you use it -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<swagger-annotations-version>1.5.8</swagger-annotations-version>
<jersey-version>2.27</jersey-version>
<jackson-version>2.8.9</jackson-version>
<jackson-databind-nullable-version>0.2.0</jackson-databind-nullable-version>
<jodatime-version>2.7</jodatime-version>
<maven-plugin-version>1.0.0</maven-plugin-version>
<junit-version>4.8.1</junit-version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,8 @@ public void processOpts() {
importMapping.put("JsonTypeInfo", "com.fasterxml.jackson.annotation.JsonTypeInfo");
importMapping.put("JsonCreator", "com.fasterxml.jackson.annotation.JsonCreator");
importMapping.put("JsonValue", "com.fasterxml.jackson.annotation.JsonValue");
importMapping.put("JsonIgnore", "com.fasterxml.jackson.annotation.JsonIgnore");
importMapping.put("JsonInclude", "com.fasterxml.jackson.annotation.JsonInclude");
importMapping.put("SerializedName", "com.google.gson.annotations.SerializedName");
importMapping.put("TypeAdapter", "com.google.gson.TypeAdapter");
importMapping.put("JsonAdapter", "com.google.gson.annotations.JsonAdapter");
Expand Down Expand Up @@ -800,7 +802,13 @@ public String toDefaultValue(Schema p) {
}
}
return null;
} else if (ModelUtils.isObjectSchema(p)) {
if (p.getDefault() != null) {
return super.toDefaultValue(p);
}
return null;
wing328 marked this conversation as resolved.
Show resolved Hide resolved
}

return super.toDefaultValue(p);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.openapitools.codegen.languages.features.GzipFeatures;
import org.openapitools.codegen.languages.features.PerformBeanValidationFeatures;
import org.openapitools.codegen.templating.mustache.CaseFormatLambda;
import org.openapitools.codegen.utils.ModelUtils;
import org.openapitools.codegen.utils.ProcessUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -583,6 +584,7 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
if (additionalProperties.containsKey("jackson")) {
model.imports.add("JsonProperty");
model.imports.add("JsonValue");
model.imports.add("JsonInclude");
}
if (additionalProperties.containsKey("gson")) {
model.imports.add("SerializedName");
Expand Down Expand Up @@ -623,6 +625,39 @@ public Map<String, Object> postProcessModelsEnum(Map<String, Object> objs) {
return objs;
}

@Override
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
objs = super.postProcessModels(objs);
if (additionalProperties.containsKey("jackson") && !JERSEY1.equals(getLibrary())) {
List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
List<Object> models = (List<Object>) objs.get("models");
for (Object _mo : models) {
Map<String, Object> mo = (Map<String, Object>) _mo;
CodegenModel cm = (CodegenModel) mo.get("model");
boolean addImports = false;
for (CodegenProperty var : cm.vars) {
boolean isOptionalNullable = Boolean.FALSE.equals(var.required) && Boolean.TRUE.equals(var.isNullable);
// only add JsonNullable and related imports to optional and nullable values
addImports |= isOptionalNullable;
var.getVendorExtensions().put("isJacksonOptionalNullable", isOptionalNullable);
}
if (addImports) {
cm.imports.add("JsonNullable");
Map<String, String> itemJsonNullable = new HashMap<String, String>();
itemJsonNullable.put("import", "org.openapitools.jackson.nullable.JsonNullable");
imports.add(itemJsonNullable);

cm.imports.add("NoSuchElementException");
Map<String, String> itemExc = new HashMap<String, String>();
itemExc.put("import", "java.util.NoSuchElementException");
imports.add(itemExc);
}
}
}

return objs;
}

public void setUseRxJava(boolean useRxJava) {
this.useRxJava = useRxJava;
doNotUseRx = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{{!
If this is map and items are nullable, make sure that nulls are included.
To determine what JsonInclude.Include method to use, consider the following:
* If the field is required, always include it, even if it is null.
* Else use custom behaviour, IOW use whatever is defined on the object mapper
}}
@JsonProperty(JSON_PROPERTY_{{nameInSnakeCase}})
@JsonInclude({{#isMapContainer}}{{#items.isNullable}}content = JsonInclude.Include.ALWAYS, {{/items.isNullable}}{{/isMapContainer}}value = JsonInclude.Include.{{#required}}ALWAYS{{/required}}{{^required}}USE_DEFAULTS{{/required}})
{{#withXml}}
{{^isContainer}}
@JacksonXmlProperty({{#isXmlAttribute}}isAttribute = true, {{/isXmlAttribute}}{{#xmlNamespace}}namespace="{{xmlNamespace}}", {{/xmlNamespace}}localName = "{{#xmlName}}{{xmlName}}{{/xmlName}}{{^xmlName}}{{baseName}}{{/xmlName}}")
{{/isContainer}}
{{#isContainer}}
{{#isXmlWrapped}}
// items.xmlName={{items.xmlName}}
@JacksonXmlElementWrapper(useWrapping = {{isXmlWrapped}}, {{#xmlNamespace}}namespace="{{xmlNamespace}}", {{/xmlNamespace}}localName = "{{#items.xmlName}}{{items.xmlName}}{{/items.xmlName}}{{^items.xmlName}}{{items.baseName}}{{/items.xmlName}}")
{{/isXmlWrapped}}
{{/isContainer}}
{{/withXml}}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.threeten.bp.*;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.openapitools.jackson.nullable.JsonNullableModule;
{{#joda}}
import com.fasterxml.jackson.datatype.joda.JodaModule;
{{/joda}}
Expand Down Expand Up @@ -177,6 +178,8 @@ public class ApiClient {
module.addDeserializer(ZonedDateTime.class, CustomInstantDeserializer.ZONED_DATE_TIME);
objectMapper.registerModule(module);
{{/threetenbp}}
JsonNullableModule jnm = new JsonNullableModule();
objectMapper.registerModule(jnm);
return objectMapper;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,11 @@
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind-version}</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>${jackson-databind-nullable-version}</version>
</dependency>
{{#withXml}}

<!-- XML Support -->
Expand Down Expand Up @@ -310,6 +315,7 @@
<feign-version>{{#useFeign10}}10.2.3{{/useFeign10}}{{^useFeign10}}9.7.0{{/useFeign10}}</feign-version>
<feign-form-version>2.1.0</feign-form-version>
<jackson-version>2.9.9</jackson-version>
<jackson-databind-nullable-version>0.2.0</jackson-databind-nullable-version>
<jackson-databind-version>2.9.9</jackson-databind-version>
{{#threetenbp}}
<jackson-threetenbp-version>2.6.4</jackson-threetenbp-version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {{apiPackage}}.*;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.openapitools.jackson.nullable.JsonNullableModule;
{{#joda}}
import com.fasterxml.jackson.datatype.joda.JodaModule;
{{/joda}}
Expand Down Expand Up @@ -53,6 +54,8 @@ public class ApiClient {
module.addDeserializer(ZonedDateTime.class, CustomInstantDeserializer.ZONED_DATE_TIME);
objectMapper.registerModule(module);
{{/threetenbp}}
JsonNullableModule jnm = new JsonNullableModule();
Copy link
Member

Choose a reason for hiding this comment

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

I don't think I saw this when I reviewed before. If JsonNullable provides a module which uses Jackson's APIs, then I think it will work the same across formats (json, xml, yaml). That addresses the question I previously raised.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

FTR, I also made a PR for jackson-databind-nullable to document how to use JsonNullable with jackson's XML-serialization: https://github.com/OpenAPITools/jackson-databind-nullable/pull/11/files

objectMapper.registerModule(jnm);
return objectMapper;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,11 @@
<artifactId>jackson-databind</artifactId>
<version>${jackson-version}</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>${jackson-databind-nullable-version}</version>
</dependency>
{{#withXml}}
<!-- XML processing: Jackson -->
<dependency>
Expand Down Expand Up @@ -303,6 +308,7 @@
<jersey-common-version>2.25.1</jersey-common-version>
<jackson-version>2.9.9</jackson-version>
<jackson-databind-version>2.9.9</jackson-databind-version>
<jackson-databind-nullable-version>0.2.0</jackson-databind-nullable-version>
{{#joda}}
<jodatime-version>2.9.9</jodatime-version>
{{/joda}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.threeten.bp.*;
{{/threetenbp}}
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.*;
import org.openapitools.jackson.nullable.JsonNullableModule;
{{#java8}}
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
{{/java8}}
Expand Down Expand Up @@ -45,6 +46,8 @@ public class JSON implements ContextResolver<ObjectMapper> {
module.addDeserializer(ZonedDateTime.class, CustomInstantDeserializer.ZONED_DATE_TIME);
mapper.registerModule(module);
{{/threetenbp}}
JsonNullableModule jnm = new JsonNullableModule();
mapper.registerModule(jnm);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,11 @@
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind-version}</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>${jackson-databind-nullable-version}</version>
</dependency>
{{#withXml}}

<!-- XML processing: JAXB -->
Expand Down Expand Up @@ -357,6 +362,7 @@
{{/supportJava6}}
<jackson-version>2.9.9</jackson-version>
<jackson-databind-version>2.9.9</jackson-databind-version>
<jackson-databind-nullable-version>0.2.0</jackson-databind-nullable-version>
{{#threetenbp}}
<threetenbp-version>2.6.4</threetenbp-version>
{{/threetenbp}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.openapitools.jackson.nullable.JsonNullableModule;

import java.net.URI;
import java.net.URLEncoder;
Expand Down Expand Up @@ -151,6 +152,8 @@ public class ApiClient {
mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
mapper.registerModule(new JavaTimeModule());
JsonNullableModule jnm = new JsonNullableModule();
mapper.registerModule(jnm);
URI baseURI = URI.create("{{{basePath}}}");
scheme = baseURI.getScheme();
host = baseURI.getHost();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson-version}</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>${jackson-databind-nullable-version}</version>
</dependency>

<!-- @Nullable annotation -->
<dependency>
Expand All @@ -210,6 +215,7 @@
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<jackson-version>2.9.9</jackson-version>
<jackson-databind-nullable-version>0.2.0</jackson-databind-nullable-version>
<junit-version>4.12</junit-version>
</properties>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package {{invokerPackage}};

import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.*;
import org.openapitools.jackson.nullable.JsonNullableModule;
{{#java8}}
import com.fasterxml.jackson.datatype.jsr310.*;
{{/java8}}
Expand All @@ -26,6 +27,8 @@ public class JSON implements ContextResolver<ObjectMapper> {
mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
mapper.setDateFormat(new RFC3339DateFormat());
JsonNullableModule jnm = new JsonNullableModule();
mapper.registerModule(jnm);
{{#java8}}
mapper.registerModule(new JavaTimeModule());
{{/java8}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind-version}</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>${jackson-databind-nullable-version}</version>
</dependency>
{{#withXml}}

<!-- XML processing: Jackson -->
Expand Down Expand Up @@ -291,6 +296,7 @@
<resteasy-version>3.1.3.Final</resteasy-version>
<jackson-version>2.9.9</jackson-version>
<jackson-databind-version>2.9.9</jackson-databind-version>
<jackson-databind-nullable-version>0.2.0</jackson-databind-nullable-version>
<threetenbp-version>2.6.4</threetenbp-version>
{{^java8}}
<jodatime-version>2.9.9</jodatime-version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import com.fasterxml.jackson.datatype.threetenbp.ThreeTenModule;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.openapitools.jackson.nullable.JsonNullableModule;
{{/threetenbp}}

import java.io.BufferedReader;
Expand Down Expand Up @@ -661,6 +662,7 @@ public class ApiClient {
messageConverters.add(new MappingJackson2HttpMessageConverter());
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
xmlMapper.registerModule(new JsonNullableModule());
messageConverters.add(new MappingJackson2XmlHttpMessageConverter(xmlMapper));

RestTemplate restTemplate = new RestTemplate(messageConverters);
Expand All @@ -674,6 +676,7 @@ public class ApiClient {
module.addDeserializer(OffsetDateTime.class, CustomInstantDeserializer.OFFSET_DATE_TIME);
module.addDeserializer(ZonedDateTime.class, CustomInstantDeserializer.ZONED_DATE_TIME);
mapper.registerModule(module);
mapper.registerModule(new JsonNullableModule());
}
}
{{/threetenbp}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,11 @@
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson-version}</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>${jackson-databind-nullable-version}</version>
</dependency>
{{#withXml}}

<!-- XML processing: Jackson -->
Expand Down Expand Up @@ -306,6 +311,7 @@
<spring-web-version>4.3.9.RELEASE</spring-web-version>
<jackson-version>2.9.9</jackson-version>
<jackson-databind-version>2.9.9</jackson-databind-version>
<jackson-databind-nullable-version>0.2.0</jackson-databind-nullable-version>
{{#joda}}
<jodatime-version>2.9.9</jodatime-version>
{{/joda}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import java.util.*;
import retrofit2.Retrofit;
import retrofit2.converter.scalars.ScalarsConverterFactory;
import retrofit2.converter.jackson.JacksonConverterFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.openapitools.jackson.nullable.JsonNullableModule;

import play.libs.Json;
import play.libs.ws.WSClient;
Expand Down Expand Up @@ -68,10 +70,14 @@ public class ApiClient {
auth.applyToParams(extraQueryParams, extraHeaders);
}

ObjectMapper mapper = Json.mapper();
JsonNullableModule jnm = new JsonNullableModule();
mapper.registerModule(jnm);

return new Retrofit.Builder()
.baseUrl(basePath)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(JacksonConverterFactory.create(Json.mapper()))
.addConverterFactory(JacksonConverterFactory.create(mapper))
.callFactory(new Play24CallFactory(wsClient, extraHeaders, extraQueryParams))
.addCallAdapterFactory(new Play24CallAdapterFactory())
.build()
Expand Down
Loading