Skip to content

Commit

Permalink
Add optional field mapper
Browse files Browse the repository at this point in the history
  • Loading branch information
lnash94 committed Nov 15, 2024
1 parent b6ad329 commit 4a7484a
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
* @since 1.9.0
*/
public class RecordTypeMapper extends AbstractTypeMapper {

public RecordTypeMapper(TypeReferenceTypeSymbol typeSymbol, AdditionalData additionalData) {
super(typeSymbol, additionalData);
}
Expand All @@ -74,15 +73,16 @@ public Schema getReferenceSchema(Components components) {

public static Schema getSchema(RecordTypeSymbol typeSymbol, Components components, String recordName,
AdditionalData additionalData) {
Set<String> fieldsOnlyForRequiredList = new HashSet<>();
ObjectSchema schema = new ObjectSchema();
Set<String> requiredFields = new HashSet<>();

Map<String, RecordFieldSymbol> recordFieldMap = new LinkedHashMap<>(typeSymbol.fieldDescriptors());
List<Schema> allOfSchemaList = mapIncludedRecords(typeSymbol, components, recordFieldMap, additionalData,
recordName);
recordName, fieldsOnlyForRequiredList);

Map<String, Schema> properties = mapRecordFields(recordFieldMap, components, requiredFields,
recordName, false, additionalData);
recordName, false, additionalData, fieldsOnlyForRequiredList);

Optional<TypeSymbol> restFieldType = typeSymbol.restTypeDescriptor();
if (restFieldType.isPresent()) {
Expand All @@ -94,8 +94,8 @@ public static Schema getSchema(RecordTypeSymbol typeSymbol, Components component
schema.additionalProperties(false);
}

schema.setProperties(properties);
schema.setRequired(requiredFields.stream().toList());
schema.setProperties(properties);
if (!allOfSchemaList.isEmpty()) {
ObjectSchema schemaWithAllOf = new ObjectSchema();
allOfSchemaList.add(schema);
Expand All @@ -107,7 +107,8 @@ public static Schema getSchema(RecordTypeSymbol typeSymbol, Components component

static List<Schema> mapIncludedRecords(RecordTypeSymbol typeSymbol, Components components,
Map<String, RecordFieldSymbol> recordFieldMap,
AdditionalData additionalData, String recordName) {
AdditionalData additionalData, String recordName,
Set<String> fieldsOnlyForRequiredList) {
List<Schema> allOfSchemaList = new ArrayList<>();
List<TypeSymbol> typeInclusions = typeSymbol.typeInclusions();
for (TypeSymbol typeInclusion : typeInclusions) {
Expand All @@ -124,15 +125,18 @@ static List<Schema> mapIncludedRecords(RecordTypeSymbol typeSymbol, Components c
.typeDescriptor();
Map<String, RecordFieldSymbol> includedRecordFieldMap = includedRecordTypeSymbol.fieldDescriptors();
for (Map.Entry<String, RecordFieldSymbol> includedRecordField : includedRecordFieldMap.entrySet()) {
if (!recordFieldMap.containsKey(includedRecordField.getKey())) {
continue;
}
RecordFieldSymbol recordFieldSymbol = recordFieldMap.get(includedRecordField.getKey());
RecordFieldSymbol includedRecordFieldValue = includedRecordField.getValue();

if (recordFieldSymbol == null
|| !includedRecordFieldValue.typeDescriptor().equals(recordFieldSymbol.typeDescriptor())) {
if (!includedRecordFieldValue.typeDescriptor().equals(recordFieldSymbol.typeDescriptor())) {
continue;
}
eliminateRedundantFields(recordFieldMap, additionalData, recordName, typeInclusion,
includedRecordField, recordFieldSymbol, includedRecordFieldValue);
includedRecordField, recordFieldSymbol, includedRecordFieldValue,
fieldsOnlyForRequiredList);
}
}
}
Expand All @@ -144,11 +148,15 @@ private static void eliminateRedundantFields(Map<String, RecordFieldSymbol> reco
TypeSymbol typeInclusion,
Map.Entry<String, RecordFieldSymbol> includedRecordField,
RecordFieldSymbol recordFieldSymbol,
RecordFieldSymbol includedRecordFieldValue) {
RecordFieldSymbol includedRecordFieldValue,
Set<String> fieldsOnlyForRequiredList) {

boolean recordHasDefault = recordFieldSymbol.hasDefaultValue();
boolean includedHasDefault = includedRecordFieldValue.hasDefaultValue();
boolean hasTypeInclusionName = typeInclusion.getName().isPresent();
boolean isIncludedOptional = includedRecordFieldValue.isOptional();
boolean isRecordFieldOptional = recordFieldSymbol.isOptional();
boolean recordFieldName = recordFieldSymbol.getName().isPresent();

if (recordHasDefault && includedHasDefault && hasTypeInclusionName) {
Optional<Object> recordFieldDefaultValueOpt = getRecordFieldDefaultValue(recordName,
Expand Down Expand Up @@ -199,12 +207,17 @@ private static void eliminateRedundantFields(Map<String, RecordFieldSymbol> reco
} else if (!recordHasDefault && !includedHasDefault) {
recordFieldMap.remove(includedRecordField.getKey());
}
if (!isRecordFieldOptional && isIncludedOptional && !recordHasDefault && recordFieldName) {
fieldsOnlyForRequiredList.add(MapperCommonUtils.unescapeIdentifier(recordFieldSymbol.getName().get()));
recordFieldMap.remove(includedRecordField.getKey());
}
}

public static Map<String, Schema> mapRecordFields(Map<String, RecordFieldSymbol> recordFieldMap,
Components components, Set<String> requiredFields,
String recordName, boolean treatNilableAsOptional,
AdditionalData additionalData) {
AdditionalData additionalData,
Set<String> fieldsOnlyForRequiredList) {
Map<String, Schema> properties = new LinkedHashMap<>();
for (Map.Entry<String, RecordFieldSymbol> recordField : recordFieldMap.entrySet()) {
RecordFieldSymbol recordFieldSymbol = recordField.getValue();
Expand All @@ -213,6 +226,9 @@ public static Map<String, Schema> mapRecordFields(Map<String, RecordFieldSymbol>
(!treatNilableAsOptional || !UnionTypeMapper.hasNilableType(recordFieldSymbol.typeDescriptor()))) {
requiredFields.add(recordFieldName);
}
if (!fieldsOnlyForRequiredList.isEmpty()) {
requiredFields.addAll(fieldsOnlyForRequiredList);
}
String recordFieldDescription = getRecordFieldTypeDescription(recordFieldSymbol);
Schema recordFieldSchema = TypeMapperImpl.getTypeSchema(recordFieldSymbol.typeDescriptor(),
components, additionalData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.media.Schema;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

Expand Down Expand Up @@ -114,7 +116,7 @@ public Map<String, Schema> getSchemaForRecordFields(Map<String, RecordFieldSymbo
Set<String> requiredFields, String recordName,
boolean treatNilableAsOptional) {
return RecordTypeMapper.mapRecordFields(recordFieldMap, components, requiredFields, recordName,
treatNilableAsOptional, componentMapperData);
treatNilableAsOptional, componentMapperData, new HashSet<>());
}

public TypeSymbol getReferredType(TypeSymbol typeSymbol) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,52 @@ paths:
type: array
items:
$ref: "#/components/schemas/RecD"
/recE:
post:
operationId: postRece
responses:
"201":
description: Created
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/RecE"
/recH:
post:
operationId: postRech
responses:
"201":
description: Created
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/RecH"
/recI:
post:
operationId: postReci
responses:
"201":
description: Created
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/RecI"
/recJ:
post:
operationId: postRecj
responses:
"202":
description: Accepted
content:
application/json:
schema:
$ref: "#/components/schemas/RecK"
components:
schemas:
Metadata:
Expand Down Expand Up @@ -157,6 +203,95 @@ components:
type: integer
format: int64
additionalProperties: false
RecE:
type: object
allOf:
- $ref: "#/components/schemas/RecA"
- required:
- a
- e
type: object
properties:
a:
type: string
e:
type: string
additionalProperties: false
RecF:
type: object
properties:
f:
type: integer
format: int64
additionalProperties: false
RecG:
type: object
allOf:
- $ref: "#/components/schemas/RecF"
- type: object
properties:
g:
type: integer
format: int64
additionalProperties: false
RecH:
type: object
allOf:
- $ref: "#/components/schemas/RecG"
- required:
- f
- g
- h
type: object
properties:
h:
type: string
additionalProperties: false
RecI:
type: object
allOf:
- $ref: "#/components/schemas/RecG"
- required:
- g
- i
type: object
properties:
f:
type: integer
format: int64
default: 10
i:
type: string
additionalProperties: false
RecK:
type: object
allOf:
- $ref: "#/components/schemas/RecA"
- $ref: "#/components/schemas/RecF"
- $ref: "#/components/schemas/RecL"
- required:
- a
- first-name
- k
type: object
properties:
k:
type: integer
format: int64
a:
type: string
additionalProperties: false
RecL:
required:
- id
type: object
properties:
first-name:
type: string
id:
type: integer
format: int64
additionalProperties: false
Resource:
type: object
allOf:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,57 @@ type RecD record {|
int d;
|};

// defaultable `a`` makes requried
type RecE record {|
*RecA;
string a;
string e;
|};

//optional test cases
type RecF record {|
int f?;
|};

type RecG record {|
*RecF;
int g?;
|};

type RecH record {|
*RecG;
int f;
int g;
string h;
|};

// optional with default value
type RecI record {|
*RecG;
int f = 10;
string i;
int g;
|};

type RecJ record {|
*http:Accepted;
RecK body;
|};

type RecK record {|
*RecA;
*RecF;
*RecL;
int k;
string a;
string first\-name;
|};

type RecL record {|
string first\-name?;
int id;
|};

service /payloadV on new http:Listener(7080) {
resource function get pods() returns Pod[] {
return [];
Expand All @@ -92,4 +143,29 @@ service /payloadV on new http:Listener(7080) {
resource function post recD() returns RecD[] {
return [];
}

resource function post recE() returns RecE[] {
return [];
}

resource function post recH() returns RecH[] {
return [];
}

resource function post recI() returns RecI[] {
return [];
}

resource function post recJ() returns RecJ {
return {
body:
{
k: 10,
aa: "abc",
a: "abcd",
id: 11,
first\-name: "lnash"
}
};
}
}

0 comments on commit 4a7484a

Please sign in to comment.