diff --git a/.github/workflows/build-timestamped-master.yml b/.github/workflows/build-timestamped-master.yml
index 72d594a2..9204231b 100644
--- a/.github/workflows/build-timestamped-master.yml
+++ b/.github/workflows/build-timestamped-master.yml
@@ -14,5 +14,5 @@ jobs:
call_workflow:
name: Run Build Workflow
if: ${{ github.repository_owner == 'ballerina-platform' }}
- uses: ballerina-platform/ballerina-library/.github/workflows/build-timestamp-master-template.yml@main
+ uses: ballerina-platform/ballerina-library/.github/workflows/build-timestamp-master-template.yml@2201.10.x
secrets: inherit
diff --git a/.github/workflows/build-with-bal-test-graalvm.yml b/.github/workflows/build-with-bal-test-graalvm.yml
index 291054d4..acbc5eab 100644
--- a/.github/workflows/build-with-bal-test-graalvm.yml
+++ b/.github/workflows/build-with-bal-test-graalvm.yml
@@ -20,6 +20,7 @@ on:
pull_request:
branches:
- main
+ - 1.0.x
types: [ opened, synchronize, reopened, labeled, unlabeled ]
concurrency:
@@ -30,7 +31,7 @@ jobs:
call_stdlib_workflow:
name: Run StdLib Workflow
if: ${{ github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository_owner == 'ballerina-platform') }}
- uses: ballerina-platform/ballerina-library/.github/workflows/build-with-bal-test-graalvm-template.yml@main
+ uses: ballerina-platform/ballerina-library/.github/workflows/build-with-bal-test-graalvm-template.yml@2201.10.x
with:
lang_tag: ${{ inputs.lang_tag }}
lang_version: ${{ inputs.lang_version }}
diff --git a/.github/workflows/central-publish.yml b/.github/workflows/central-publish.yml
index 11922b55..74c48557 100644
--- a/.github/workflows/central-publish.yml
+++ b/.github/workflows/central-publish.yml
@@ -15,7 +15,7 @@ jobs:
call_workflow:
name: Run Central Publish Workflow
if: ${{ github.repository_owner == 'ballerina-platform' }}
- uses: ballerina-platform/ballerina-library/.github/workflows/central-publish-template.yml@main
+ uses: ballerina-platform/ballerina-library/.github/workflows/central-publish-template.yml@2201.10.x
secrets: inherit
with:
environment: ${{ github.event.inputs.environment }}
diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml
index c6044e4c..4488b8fd 100644
--- a/.github/workflows/publish-release.yml
+++ b/.github/workflows/publish-release.yml
@@ -9,7 +9,7 @@ jobs:
call_workflow:
name: Run Release Workflow
if: ${{ github.repository_owner == 'ballerina-platform' }}
- uses: ballerina-platform/ballerina-library/.github/workflows/release-package-template.yml@main
+ uses: ballerina-platform/ballerina-library/.github/workflows/release-package-template.yml@2201.10.x
secrets: inherit
with:
package-name: data.xmldata
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index 06f4f569..7b455672 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -10,5 +10,5 @@ jobs:
call_workflow:
name: Run PR Build Workflow
if: ${{ github.repository_owner == 'ballerina-platform' }}
- uses: ballerina-platform/ballerina-library/.github/workflows/pull-request-build-template.yml@main
+ uses: ballerina-platform/ballerina-library/.github/workflows/pull-request-build-template.yml@2201.10.x
secrets: inherit
diff --git a/.github/workflows/trivy-scan.yml b/.github/workflows/trivy-scan.yml
index c02c8ff4..c29d8f2a 100644
--- a/.github/workflows/trivy-scan.yml
+++ b/.github/workflows/trivy-scan.yml
@@ -9,5 +9,5 @@ jobs:
call_workflow:
name: Run Trivy Scan Workflow
if: ${{ github.repository_owner == 'ballerina-platform' }}
- uses: ballerina-platform/ballerina-library/.github/workflows/trivy-scan-template.yml@main
+ uses: ballerina-platform/ballerina-library/.github/workflows/trivy-scan-template.yml@2201.10.x
secrets: inherit
diff --git a/ballerina/Ballerina.toml b/ballerina/Ballerina.toml
index 65c23573..55e32b53 100644
--- a/ballerina/Ballerina.toml
+++ b/ballerina/Ballerina.toml
@@ -1,7 +1,7 @@
[package]
org = "ballerina"
name = "data.xmldata"
-version = "1.0.0"
+version = "1.1.0"
authors = ["Ballerina"]
keywords = ["xml"]
repository = "https://github.com/ballerina-platform/module-ballerina-data-xmldata"
@@ -12,8 +12,8 @@ export = ["data.xmldata"]
[[platform.java17.dependency]]
groupId = "io.ballerina.lib"
artifactId = "data-native"
-version = "1.0.0"
-path = "../native/build/libs/data.xmldata-native-1.0.0.jar"
+version = "1.1.0"
+path = "../native/build/libs/data.xmldata-native-1.1.0-SNAPSHOT.jar"
[[platform.java17.dependency]]
groupId = "io.ballerina.stdlib"
diff --git a/ballerina/CompilerPlugin.toml b/ballerina/CompilerPlugin.toml
index 1669a303..2eb00ce5 100644
--- a/ballerina/CompilerPlugin.toml
+++ b/ballerina/CompilerPlugin.toml
@@ -3,4 +3,4 @@ id = "constraint-compiler-plugin"
class = "io.ballerina.lib.data.xmldata.compiler.XmldataCompilerPlugin"
[[dependency]]
-path = "../compiler-plugin/build/libs/data.xmldata-compiler-plugin-1.0.0.jar"
+path = "../compiler-plugin/build/libs/data.xmldata-compiler-plugin-1.1.0-SNAPSHOT.jar"
diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml
index 0180731c..b3e73938 100644
--- a/ballerina/Dependencies.toml
+++ b/ballerina/Dependencies.toml
@@ -22,7 +22,7 @@ modules = [
[[package]]
org = "ballerina"
name = "data.xmldata"
-version = "1.0.0"
+version = "1.1.0"
dependencies = [
{org = "ballerina", name = "constraint"},
{org = "ballerina", name = "io"},
diff --git a/ballerina/tests/test_finite_types.bal b/ballerina/tests/test_finite_types.bal
new file mode 100644
index 00000000..6b6a0707
--- /dev/null
+++ b/ballerina/tests/test_finite_types.bal
@@ -0,0 +1,199 @@
+// Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/test;
+
+enum EnumA {
+ A = "A",
+ B,
+ C = "C2"
+}
+
+type FiniteType true|"A"|1|2;
+
+@test:Config
+function testFiniteTypes() returns error? {
+ record {|
+ EnumA a;
+ "A"|"B"|"C" b;
+ record {|
+ "A"|"B"|"C" c;
+ EnumA d;
+ |} nested;
+ |} r = check parseAsType(xml `ABBB`);
+ test:assertEquals(r, {a: "A", b: "B", nested: {c: "B", d: "B"}});
+}
+
+@test:Config
+function testFiniteTypesWithNestedRecords() returns error? {
+ record {|
+ EnumA a;
+ FiniteType b;
+ record {|
+ FiniteType c;
+ FiniteType e;
+ EnumA d;
+ |} nested;
+ |} r = check parseAsType(xml `C212Atrue`);
+ test:assertEquals(r, {a: "C2", b: 1, nested: {c: 2, d: "A", e: true}});
+}
+
+@test:Config
+function testFiniteTypeArrays() returns error? {
+ record {|
+ EnumA[] a;
+ ("A"|"B"|"C")[] b;
+ record {|
+ ("A"|"B"|"C")[] c;
+ EnumA[] d;
+ |} nested;
+ |} r = check parseAsType(xml `AABBBBBB`);
+ test:assertEquals(r, {a: ["A", "A"], b: ["B", "B"], nested: {c: ["B", "B"], d: ["B", "B"]}});
+}
+
+@test:Config
+function testFiniteTypeArrays2() returns error? {
+ record {|
+ EnumA[] a;
+ FiniteType[] b;
+ record {|
+ FiniteType[] c;
+ FiniteType[] e;
+ EnumA[] d;
+ |} nested;
+ |} r = check parseAsType(xml `C2C21122AAtruetrue`);
+ test:assertEquals(r, {a: ["C2", "C2"], b: [1, 1], nested: {c: [2, 2], d: ["A", "A"], e: [true, true]}});
+}
+
+@test:Config
+function testFiniteTypesWithXmlString() returns error? {
+ record {|
+ EnumA a;
+ "A"|"B"|"C" b;
+ record {|
+ "A"|"B"|"C" c;
+ EnumA d;
+ |} nested;
+ |} r = check parseString(string `ABBB`);
+ test:assertEquals(r, {a: "A", b: "B", nested: {c: "B", d: "B"}});
+}
+
+@test:Config
+function testFiniteTypesWithNestedRecordsWithXmlString() returns error? {
+ record {|
+ EnumA a;
+ FiniteType b;
+ record {|
+ FiniteType c;
+ FiniteType e;
+ EnumA d;
+ |} nested;
+ |} r = check parseString(string `C212Atrue`);
+ test:assertEquals(r, {a: "C2", b: 1, nested: {c: 2, d: "A", e: true}});
+}
+
+@test:Config
+function testFiniteTypeArraysWithXmlString() returns error? {
+ record {|
+ EnumA[] a;
+ ("A"|"B"|"C")[] b;
+ record {|
+ ("A"|"B"|"C")[] c;
+ EnumA[] d;
+ |} nested;
+ |} r = check parseString(string `AABBBBBB`);
+ test:assertEquals(r, {a: ["A", "A"], b: ["B", "B"], nested: {c: ["B", "B"], d: ["B", "B"]}});
+}
+
+@test:Config
+function testFiniteTypeArraysWithXmlString2() returns error? {
+ record {|
+ EnumA[] a;
+ FiniteType[] b;
+ record {|
+ FiniteType[] c;
+ FiniteType[] e;
+ EnumA[] d;
+ |} nested;
+ |} r = check parseString(string `C2C21122AAtruetrue`);
+ test:assertEquals(r, {a: ["C2", "C2"], b: [1, 1], nested: {c: [2, 2], d: ["A", "A"], e: [true, true]}});
+}
+type NestedRec record {|
+ @Name {
+ value: "c2"
+ }
+ FiniteType c;
+ FiniteType e;
+ @Name {
+ value: "d2"
+ }
+ EnumA d;
+|};
+
+@test:Config
+function testFiniteTypesWithNameAnnotations() returns error? {
+ record {|
+ EnumA a;
+ FiniteType b;
+ NestedRec nested;
+ |} r = check parseAsType(xml `C212Atrue`);
+ test:assertEquals(r, {a: "C2", b: 1, nested: {c: 2, d: "A", e: true}});
+}
+
+type FiniteValue 100f;
+
+@test:Config
+function testRecordFieldWithSingleFiniteType() returns error? {
+ record {|
+ EnumA a;
+ "A" b;
+ record {|
+ FiniteValue c;
+ EnumA d;
+ |} nested;
+ |} r = check parseAsType(xml `AA100.0B`);
+ test:assertEquals(r, {a: "A", b: "A", nested: {c: 100f, d: "B"}});
+}
+
+@test:Config
+function testRecordFieldWithSingleFiniteType2() returns error? {
+ record {|
+ 100f a;
+ 200.1d b;
+ 100d c;
+ 200.1f d;
+ 100f e;
+ 200.1d f;
+ 100d g;
+ 200.1f h;
+ |} r = check parseAsType(xml `100200.1100200.1100.0200.1100.0200.1`);
+ test:assertEquals(r, {a: 100f, b: 200.1d, c: 100d, d: 200.1f, e: 100f, f: 200.1d, g: 100d, h: 200.1f});
+}
+
+@test:Config
+function testRecordFieldWithSingleFiniteType3() returns error? {
+ record {|
+ 100f a;
+ |}|Error r = parseAsType(xml `100.01`);
+ test:assertTrue(r is Error);
+ test:assertEquals((r).message(), "'string' value '100.01' cannot be converted to '100.0f'");
+
+ record {|
+ 100d a;
+ |}|Error r2 = parseAsType(xml `100.01`);
+ test:assertTrue(r2 is Error);
+ test:assertEquals((r2).message(), "'string' value '100.01' cannot be converted to '100d'");
+}
diff --git a/gradle.properties b/gradle.properties
index 34a6b716..e66aae1f 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,6 +1,6 @@
org.gradle.caching=true
group=io.ballerina.lib
-version=1.0.0
+version=1.1.0-SNAPSHOT
ballerinaLangVersion=2201.10.0
checkstyleToolVersion=10.12.0
diff --git a/native/src/main/java/io/ballerina/lib/data/xmldata/FromString.java b/native/src/main/java/io/ballerina/lib/data/xmldata/FromString.java
index d48b9425..22d9a862 100644
--- a/native/src/main/java/io/ballerina/lib/data/xmldata/FromString.java
+++ b/native/src/main/java/io/ballerina/lib/data/xmldata/FromString.java
@@ -24,15 +24,18 @@
import io.ballerina.runtime.api.TypeTags;
import io.ballerina.runtime.api.creators.TypeCreator;
import io.ballerina.runtime.api.creators.ValueCreator;
+import io.ballerina.runtime.api.types.FiniteType;
import io.ballerina.runtime.api.types.ReferenceType;
import io.ballerina.runtime.api.types.Type;
import io.ballerina.runtime.api.types.UnionType;
+import io.ballerina.runtime.api.utils.StringUtils;
import io.ballerina.runtime.api.utils.TypeUtils;
import io.ballerina.runtime.api.values.BDecimal;
import io.ballerina.runtime.api.values.BError;
import io.ballerina.runtime.api.values.BString;
import io.ballerina.runtime.api.values.BTypedesc;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@@ -96,6 +99,8 @@ public static Object fromStringWithType(BString string, Type expType) {
return stringToUnion(string, JSON_TYPE_WITH_BASIC_TYPES);
case TypeTags.TYPE_REFERENCED_TYPE_TAG:
return fromStringWithType(string, ((ReferenceType) expType).getReferredType());
+ case TypeTags.FINITE_TYPE_TAG:
+ return stringToFiniteType(value, (FiniteType) expType);
default:
return returnError(value, expType.toString());
}
@@ -104,6 +109,38 @@ public static Object fromStringWithType(BString string, Type expType) {
}
}
+ private static Object stringToFiniteType(String value, FiniteType finiteType) {
+ return finiteType.getValueSpace().stream()
+ .filter(finiteValue -> !(convertToSingletonValue(value, finiteValue) instanceof BError))
+ .findFirst()
+ .orElseGet(() -> returnError(value, finiteType.toString()));
+ }
+
+ private static Object convertToSingletonValue(String str, Object singletonValue) {
+ String singletonStr = String.valueOf(singletonValue);
+ Type type = TypeUtils.getType(singletonValue);
+
+ if (singletonValue instanceof BDecimal decimalValue) {
+ BigDecimal bigDecimal = decimalValue.decimalValue();
+ if (bigDecimal.compareTo(new BigDecimal(str)) == 0) {
+ return fromStringWithType(StringUtils.fromString(str), type);
+ }
+ return returnError(str, singletonStr);
+ }
+
+ if (singletonValue instanceof Double doubleValue) {
+ if (doubleValue.compareTo(Double.valueOf(str)) == 0) {
+ return fromStringWithType(StringUtils.fromString(str), type);
+ }
+ return returnError(str, singletonStr);
+ }
+
+ if (str.equals(singletonStr)) {
+ return fromStringWithType(StringUtils.fromString(str), type);
+ }
+ return returnError(str, singletonStr);
+ }
+
private static Long stringToInt(String value) throws NumberFormatException {
return Long.parseLong(value);
}
diff --git a/native/src/main/java/io/ballerina/lib/data/xmldata/utils/DataUtils.java b/native/src/main/java/io/ballerina/lib/data/xmldata/utils/DataUtils.java
index 5e59ab97..1f7f8e68 100644
--- a/native/src/main/java/io/ballerina/lib/data/xmldata/utils/DataUtils.java
+++ b/native/src/main/java/io/ballerina/lib/data/xmldata/utils/DataUtils.java
@@ -316,7 +316,7 @@ public static boolean isSupportedType(Type type) {
switch (type.getTag()) {
case TypeTags.NULL_TAG, TypeTags.INT_TAG, TypeTags.BYTE_TAG, TypeTags.FLOAT_TAG, TypeTags.DECIMAL_TAG,
TypeTags.BOOLEAN_TAG, TypeTags.STRING_TAG, TypeTags.RECORD_TYPE_TAG, TypeTags.MAP_TAG,
- TypeTags.JSON_TAG, TypeTags.ANYDATA_TAG -> {
+ TypeTags.JSON_TAG, TypeTags.ANYDATA_TAG, TypeTags.FINITE_TYPE_TAG -> {
return true;
}
case TypeTags.ARRAY_TAG -> {
diff --git a/native/src/main/java/io/ballerina/lib/data/xmldata/xml/XmlParser.java b/native/src/main/java/io/ballerina/lib/data/xmldata/xml/XmlParser.java
index 8f36c4fa..71a33e00 100644
--- a/native/src/main/java/io/ballerina/lib/data/xmldata/xml/XmlParser.java
+++ b/native/src/main/java/io/ballerina/lib/data/xmldata/xml/XmlParser.java
@@ -428,7 +428,7 @@ private Object convertStringToRestExpType(BString value, Type expType) {
return convertStringToRestExpType(value, ((ArrayType) expType).getElementType());
}
case TypeTags.INT_TAG, TypeTags.FLOAT_TAG, TypeTags.DECIMAL_TAG, TypeTags.STRING_TAG,
- TypeTags.BOOLEAN_TAG, TypeTags.UNION_TAG -> {
+ TypeTags.BOOLEAN_TAG, TypeTags.UNION_TAG, TypeTags.FINITE_TYPE_TAG -> {
return convertStringToExpType(value, expType);
}
case TypeTags.ANYDATA_TAG, TypeTags.JSON_TAG -> {