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] fix #18735 Allow specialized containerDefaultToNull #19423

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.openapitools.codegen;

import io.swagger.v3.oas.models.media.Schema;

import java.util.List;

public class ContainerDefaultEvaluator {

final List<ContainerDefaultParser.Condition> conditions;

public ContainerDefaultEvaluator(String containerDefaultToNull) {
conditions = ContainerDefaultParser.parseExpression(containerDefaultToNull);
}

public boolean isNullDefault(CodegenProperty cp, Schema schema) {
ContainerDefaultParser.NullableState nullable;
if (schema.getNullable() == null && (schema.getExtensions() == null || !schema.getExtensions().containsKey("x-nullable"))) {
nullable = ContainerDefaultParser.NullableState.UNSPECIFIED;
} else {
if (cp.isNullable) {
nullable = ContainerDefaultParser.NullableState.YES;
} else {
nullable = ContainerDefaultParser.NullableState.NO;
}
}

return conditions.stream().anyMatch(
myCondition ->
(myCondition.getRequired() == null || myCondition.getRequired().equals(cp.required))
&& (myCondition.getNullable() == null || myCondition.getNullable().equals(nullable))
);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package org.openapitools.codegen;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;

class ContainerDefaultParser {

protected static final String REQUIRED = "required";
protected static final String NULLABLE = "nullable";
protected static final String ERROR_UNEXPECTED = "unexpected containerDefaultToNull keyword: ";

protected static List<Condition> parseExpression(String input) {
if (input == null || "".equals(input.trim())) {
input = "7.5.0";
}

String[] orConditions = input.split("\\|");
List<Condition> conditions = new ArrayList<>();

for (String myOrCondition : orConditions) {
conditions.addAll(parseCondition(myOrCondition.trim()));
}

return conditions;
}

protected static List<Condition> parseCondition(String conditionStr) {
String[] andConditions = conditionStr.split("&");
Boolean required = null;
NullableState nullable = null;

for (String myAndCondition : andConditions) {
String trimmed = myAndCondition.trim();

if (trimmed.startsWith("!")) {
String keyword = trimmed.substring(1).trim();
if (keyword.equals(REQUIRED)) {
required = false;
} else if (keyword.equals(NULLABLE)) {
nullable = NullableState.NO;
} else {
throw new IllegalArgumentException(ERROR_UNEXPECTED + keyword);
}
} else if (trimmed.startsWith("?")) {
String keyword = trimmed.substring(1).trim();
if (keyword.equals(NULLABLE)) {
nullable = NullableState.UNSPECIFIED;
} else {
throw new IllegalArgumentException(ERROR_UNEXPECTED + keyword);
}
} else {
switch (trimmed) {
case REQUIRED:
required = true;
break;
case NULLABLE:
nullable = NullableState.YES;
break;
case "7.5.0":
case "false":
return List.of(
new Condition(true, NullableState.YES),
new Condition(false, NullableState.YES));
case "7.4.0":
return List.of(
new Condition(true, NullableState.YES),
new Condition(false, NullableState.YES),
new Condition(false, NullableState.NO),
new Condition(false, NullableState.UNSPECIFIED));
case "true":
return List.of(
new Condition(true, NullableState.YES),
new Condition(true, NullableState.NO),
new Condition(true, NullableState.UNSPECIFIED),
new Condition(false, NullableState.YES),
new Condition(false, NullableState.NO),
new Condition(false, NullableState.UNSPECIFIED));
case "none":
return new ArrayList<>();
default:
throw new IllegalArgumentException(ERROR_UNEXPECTED + trimmed);
}
}
}

return List.of(new Condition(required, nullable));
}

protected enum NullableState {
YES, NO, UNSPECIFIED
}

@Data
protected static class Condition {
private final Boolean required;
private final NullableState nullable;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
@Setter protected String implicitHeadersRegex = null;
@Setter protected boolean camelCaseDollarSign = false;
@Setter protected boolean useJakartaEe = false;
@Setter protected boolean containerDefaultToNull = false;
@Setter protected String containerDefaultToNull = "false";
@Getter @Setter
protected boolean generateConstructorWithAllArgs = false;
@Getter @Setter
Expand All @@ -189,6 +189,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
@Getter @Setter
protected boolean useBeanValidation = false;
private Map<String, String> schemaKeyToModelNameCache = new HashMap<>();
private ContainerDefaultEvaluator containerDefaultEvaluator = new ContainerDefaultEvaluator("false");

public AbstractJavaCodegen() {
super();
Expand Down Expand Up @@ -636,7 +637,7 @@ public void processOpts() {
applyJavaxPackage();
}

convertPropertyToBooleanAndWriteBack(CONTAINER_DEFAULT_TO_NULL, this::setContainerDefaultToNull);
convertPropertyToStringAndWriteBack(CONTAINER_DEFAULT_TO_NULL, this::setContainerDefaultToNull);

additionalProperties.put("sanitizeGeneric", (Mustache.Lambda) (fragment, writer) -> {
String content = fragment.execute();
Expand All @@ -645,6 +646,8 @@ public void processOpts() {
}
writer.write(content);
});

this.containerDefaultEvaluator = new ContainerDefaultEvaluator(this.containerDefaultToNull);
}

/**
Expand Down Expand Up @@ -1257,8 +1260,7 @@ public String toDefaultValue(CodegenProperty cp, Schema schema) {
schema = ModelUtils.getReferencedSchema(this.openAPI, schema);
if (ModelUtils.isArraySchema(schema)) {
if (schema.getDefault() == null) {
// nullable or containerDefaultToNull set to true
if (cp.isNullable || containerDefaultToNull) {
if (containerDefaultEvaluator.isNullDefault(cp, schema)) {
return null;
}
return getDefaultCollectionType(schema);
Expand All @@ -1273,8 +1275,7 @@ public String toDefaultValue(CodegenProperty cp, Schema schema) {
return null;
}

// nullable or containerDefaultToNull set to true
if (cp.isNullable || containerDefaultToNull) {
if (containerDefaultEvaluator.isNullDefault(cp, schema)) {
return null;
}

Expand Down
Loading
Loading