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

Fix incorrect null value for xml attributes when the expected field type is an array #44

Merged
merged 8 commits into from
Nov 29, 2024
1 change: 1 addition & 0 deletions ballerina/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,4 @@ dependencies = [
modules = [
{org = "ballerina", packageName = "time", moduleName = "time"}
]

57 changes: 57 additions & 0 deletions ballerina/tests/fromXml_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -3635,3 +3635,60 @@ function testXmlToRecordWithInvalidExpectedTypeForText() {
test:assertTrue(rec6 is Error);
test:assertEquals((<Error>rec6).message(), "unsupported input type");
}

@test:Config {
groups: ["fromXml"]
}
function testXmlToRecordWithInvalidExpectedTypeForAttributes() {
xml value = xml `<a id="2">1</a>`;
record {int[] id;}|error rec = parseAsType(value);
test:assertTrue(rec is Error);
test:assertEquals((<error>rec).message(), "attribute 'id' cannot be converted into the array type 'int[]'");
SasinduDilshara marked this conversation as resolved.
Show resolved Hide resolved

xml value2 = xml `<a id="2">
<id id="2">1</id>
<id id="2">2</id>
<id id="2">3</id>
</a>`;

record {int[] id;}|error rec2 = parseAsType(value2);
test:assertEquals(rec2, {id:[1,2,3]});

xml value3 = xml `<a id="1"><b id="2">3</b></a>`;
record {record{int[] id;} b;}|error rec3 = parseAsType(value3);
test:assertTrue(rec3 is Error);
test:assertEquals((<error>rec3).message(), "attribute 'id' cannot be converted into the array type 'int[]'");

xml value4 = xml `<a id="2">
<id id="2">1</id>
<id id="2">2</id>
<id id="2">3</id>
</a>`;
record {record{int[] id;}[] id;}|error rec4 = parseAsType(value4);
test:assertTrue(rec4 is Error);
test:assertEquals((<error>rec4).message(), "attribute 'id' cannot be converted into the array type 'int[]'");

xml value5 = xml `<a id="2">1</a>`;
record {map<int> id;}|error rec5 = parseAsType(value5);
test:assertTrue(rec5 is Error);
test:assertEquals((<error>rec5).message(), "attribute 'id' cannot be converted into the array type 'map<int>'");

xml value6 = xml `<a id="1"><b id="2">3</b></a>`;
record {record{map<int> id;} b;}|error rec6 = parseAsType(value6);
test:assertTrue(rec6 is Error);
test:assertEquals((<error>rec6).message(), "attribute 'id' cannot be converted into the array type 'map<int>'");

xml value7 = xml `<a id="2">1</a>`;
record {string:RegExp id;}|error rec7 = parseAsType(value7);
test:assertTrue(rec7 is Error);
test:assertEquals((<error>rec7).message(), "unsupported input type");

xml value8 = xml `<a id="2">
<id id="2">1</id>
<id id="2">2</id>
<id id="2">3</id>
</a>`;
record {record{string:RegExp id;}[] id;}|error rec8 = parseAsType(value8);
test:assertTrue(rec8 is Error);
test:assertEquals((<error>rec8).message(), "unsupported input type");
}
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,27 @@ public static String generateStringFromXmlReader(Reader reader) throws IOExcepti
return builder.toString();
}

public static boolean isSupportedTypeForAttributes(Type fieldType) {
if (TypeTags.isIntegerTypeTag(fieldType.getTag())) {
return true;
}

if (TypeTags.isStringTypeTag(fieldType.getTag())) {
return true;
}

if (TypeTags.isXMLTypeTag(fieldType.getTag())) {
return false;
}

return switch (fieldType.getTag()) {
case TypeTags.FLOAT_TAG, TypeTags.BOOLEAN_TAG, TypeTags.NULL_TAG,
TypeTags.DECIMAL_TAG, TypeTags.BYTE_TAG, TypeTags.UNION_TAG, TypeTags.ANYDATA_TAG,
TypeTags.ANY_TAG, TypeTags.JSON_TAG -> true;
default -> false;
};
}

public static boolean isContainsUnionType(Type expType) {
if (expType == null) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ public enum DiagnosticErrorCode {
INVALID_SEQUENCE_ANNOTATION("XML_ERROR_0026", "invalid.sequence.annotation"),
INVALID_CHOICE_ANNOTATION("XML_ERROR_0027", "invalid.choice.annotation"),
INVALID_XSD_ANNOTATION("XML_ERROR_0028", "invalid.xsd.annotation"),
INVALID_XML("XML_ERROR_0029", "invalid.xml");
INVALID_XML("XML_ERROR_0029", "invalid.xml"),
ATTRIBUTE_CANNOT_CONVERT_INTO_ARRAY_TYPE("XML_ERROR_0031",
"attributes.cannot.convert.to.array.type"),
CANNOT_CONVERT_ATTRIBUTE_TO_ARRAY_TYPE("XML_ERROR_0032", "cannot.convert.attributes.to.array.type");

String diagnosticId;
String messageKey;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -841,9 +841,20 @@ private void handleAttributes(BXmlItem xmlItem, BMap<BString, Object> currentNod
analyzerData.rootRecord);
}

Type fieldType = field.getFieldType();

if (DataUtils.isRegExpType(fieldType)) {
throw DiagnosticLog.error(DiagnosticErrorCode.UNSUPPORTED_TYPE);
}

if (!DataUtils.isSupportedTypeForAttributes(TypeUtils.getReferredType(fieldType))) {
throw DiagnosticLog.error(DiagnosticErrorCode.CANNOT_CONVERT_ATTRIBUTE_TO_ARRAY_TYPE,
field.getFieldName(), fieldType);
}

try {
currentNode.put(StringUtils.fromString(field.getFieldName()),
DataUtils.convertStringToExpType(attributeMap.get(key), field.getFieldType()));
DataUtils.convertStringToExpType(attributeMap.get(key), fieldType));
} catch (Exception e) {
// Ignore: Expected type will mismatch when element and attribute having same name.
}
Expand Down
2 changes: 2 additions & 0 deletions native/src/main/resources/error.properties
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,5 @@ error.invalid.xsd.annotation=\

error.invalid.xml=\
Invalid XML found: ''{0}''
error.cannot.convert.attributes.to.array.type=\
attribute ''{0}'' cannot be converted into the array type ''{1}''
SasinduDilshara marked this conversation as resolved.
Show resolved Hide resolved
Loading