polyxml 0.25.0__tar.gz → 0.26.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {polyxml-0.25.0 → polyxml-0.26.0}/Cargo.lock +6 -6
- {polyxml-0.25.0 → polyxml-0.26.0}/Cargo.toml +1 -1
- {polyxml-0.25.0 → polyxml-0.26.0}/PKG-INFO +1 -1
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/codegen/java/mod.rs +154 -4
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/codegen/java/models.rs +10 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/parser.rs +26 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_java_codegen.rs +56 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_xsi_type.rs +15 -2
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-python/tests/test_xsi_type.py +19 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/pyproject.toml +1 -1
- {polyxml-0.25.0 → polyxml-0.26.0}/README.md +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/Cargo.toml +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/README.md +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/benches/tag_dispatch.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/codegen/cpp/mod.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/codegen/csharp/mod.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/codegen/go/mod.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/codegen/java/codec.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/codegen/mod.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/codegen/python/aot.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/codegen/python/mod.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/codegen/rust/mod.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/codegen/typescript/mod.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/converters.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/error.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/ir/mod.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/json.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/lib.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/schema.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/schema_parser/mod.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/serializer.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/transcoder.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/src/value.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_adversarial_identifiers.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_conformance.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_core.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_cpp_codegen.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_csharp_codegen.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_go_codegen.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_json.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_pattern_codegen.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_python_codegen.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_rust_codegen.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_schema_audit.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_schema_ir.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_security.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_transcoder.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/tests/test_unbounded_choice.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-python/Cargo.toml +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-python/README.md +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-python/benches/aot_vs_dataclass.py +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-python/src/lib.rs +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-python/tests/test_conformance.py +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-python/tests/test_generated_models.py +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-python/tests/test_json.py +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-python/tests/test_polyxml.py +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/python/polyxml/AGENT_GUIDE.md +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/python/polyxml/__init__.py +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/python/polyxml/compat/__init__.py +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/python/polyxml/compat/xsdata.py +0 -0
- {polyxml-0.25.0 → polyxml-0.26.0}/python/polyxml/py.typed +0 -0
|
@@ -608,7 +608,7 @@ dependencies = [
|
|
|
608
608
|
|
|
609
609
|
[[package]]
|
|
610
610
|
name = "polyxml"
|
|
611
|
-
version = "0.
|
|
611
|
+
version = "0.26.0"
|
|
612
612
|
dependencies = [
|
|
613
613
|
"criterion",
|
|
614
614
|
"heck",
|
|
@@ -628,14 +628,14 @@ dependencies = [
|
|
|
628
628
|
|
|
629
629
|
[[package]]
|
|
630
630
|
name = "polyxml-c"
|
|
631
|
-
version = "0.
|
|
631
|
+
version = "0.26.0"
|
|
632
632
|
dependencies = [
|
|
633
633
|
"polyxml",
|
|
634
634
|
]
|
|
635
635
|
|
|
636
636
|
[[package]]
|
|
637
637
|
name = "polyxml-cli"
|
|
638
|
-
version = "0.
|
|
638
|
+
version = "0.26.0"
|
|
639
639
|
dependencies = [
|
|
640
640
|
"clap",
|
|
641
641
|
"glob",
|
|
@@ -649,7 +649,7 @@ dependencies = [
|
|
|
649
649
|
|
|
650
650
|
[[package]]
|
|
651
651
|
name = "polyxml-js"
|
|
652
|
-
version = "0.
|
|
652
|
+
version = "0.26.0"
|
|
653
653
|
dependencies = [
|
|
654
654
|
"napi",
|
|
655
655
|
"napi-build",
|
|
@@ -659,7 +659,7 @@ dependencies = [
|
|
|
659
659
|
|
|
660
660
|
[[package]]
|
|
661
661
|
name = "polyxml-python"
|
|
662
|
-
version = "0.
|
|
662
|
+
version = "0.26.0"
|
|
663
663
|
dependencies = [
|
|
664
664
|
"lexical-core",
|
|
665
665
|
"polyxml",
|
|
@@ -669,7 +669,7 @@ dependencies = [
|
|
|
669
669
|
|
|
670
670
|
[[package]]
|
|
671
671
|
name = "polyxml-wasm"
|
|
672
|
-
version = "0.
|
|
672
|
+
version = "0.26.0"
|
|
673
673
|
dependencies = [
|
|
674
674
|
"polyxml",
|
|
675
675
|
"quick-xml",
|
|
@@ -57,6 +57,9 @@ pub struct JavaOptions {
|
|
|
57
57
|
pub emit_direct_codec: bool,
|
|
58
58
|
/// Generate facet validation in compact constructors (default: true)
|
|
59
59
|
pub validate_facets: bool,
|
|
60
|
+
/// Emit Jakarta Bean Validation annotations (adds an optional API dependency).
|
|
61
|
+
#[serde(default)]
|
|
62
|
+
pub bean_validation: bool,
|
|
60
63
|
/// Emit top-level aliases for root elements (default: true)
|
|
61
64
|
pub emit_root_aliases: bool,
|
|
62
65
|
/// Custom header text to prepend to generated files (default: None)
|
|
@@ -72,6 +75,7 @@ impl Default for JavaOptions {
|
|
|
72
75
|
emit_builder: false,
|
|
73
76
|
emit_direct_codec: false,
|
|
74
77
|
validate_facets: true,
|
|
78
|
+
bean_validation: false,
|
|
75
79
|
emit_root_aliases: true,
|
|
76
80
|
custom_header: None,
|
|
77
81
|
}
|
|
@@ -345,6 +349,9 @@ impl JavaCodegen {
|
|
|
345
349
|
out.push_str("import java.time.*;\n");
|
|
346
350
|
out.push_str("import java.math.*;\n");
|
|
347
351
|
out.push_str("import java.util.regex.Pattern;\n");
|
|
352
|
+
if self.options.bean_validation {
|
|
353
|
+
out.push_str("import jakarta.validation.constraints.*;\n");
|
|
354
|
+
}
|
|
348
355
|
|
|
349
356
|
if self.options.backend.is_jackson() {
|
|
350
357
|
out.push('\n');
|
|
@@ -454,6 +461,12 @@ impl JavaCodegen {
|
|
|
454
461
|
|
|
455
462
|
let field_type = self.field_type(field);
|
|
456
463
|
|
|
464
|
+
let bean_annotations = self.bean_annotations(field).join(" ");
|
|
465
|
+
let bean_prefix = if bean_annotations.is_empty() {
|
|
466
|
+
String::new()
|
|
467
|
+
} else {
|
|
468
|
+
format!("{bean_annotations} ")
|
|
469
|
+
};
|
|
457
470
|
if jackson {
|
|
458
471
|
let mut annotations = Vec::new();
|
|
459
472
|
// @JsonProperty
|
|
@@ -482,9 +495,12 @@ impl JavaCodegen {
|
|
|
482
495
|
}
|
|
483
496
|
|
|
484
497
|
let annotation_str = annotations.join(" ");
|
|
485
|
-
components.push(format!(
|
|
498
|
+
components.push(format!(
|
|
499
|
+
"{}{} {} {}",
|
|
500
|
+
bean_prefix, annotation_str, field_type, field_id
|
|
501
|
+
));
|
|
486
502
|
} else {
|
|
487
|
-
components.push(format!("{} {}", field_type, field_id));
|
|
503
|
+
components.push(format!("{}{} {}", bean_prefix, field_type, field_id));
|
|
488
504
|
}
|
|
489
505
|
|
|
490
506
|
if self.options.validate_facets {
|
|
@@ -714,10 +730,26 @@ impl JavaCodegen {
|
|
|
714
730
|
};
|
|
715
731
|
|
|
716
732
|
// Build the value component with optional Jackson annotations
|
|
733
|
+
let mut value_field = crate::ir::FieldDef::new(
|
|
734
|
+
"value",
|
|
735
|
+
"value",
|
|
736
|
+
crate::ir::FieldKind::Text,
|
|
737
|
+
s.base_type.clone(),
|
|
738
|
+
);
|
|
739
|
+
value_field.facets = Some(s.facets.clone());
|
|
740
|
+
let bean_prefix = self.bean_annotations(&value_field).join(" ");
|
|
741
|
+
let bean_prefix = if bean_prefix.is_empty() {
|
|
742
|
+
String::new()
|
|
743
|
+
} else {
|
|
744
|
+
format!("{bean_prefix} ")
|
|
745
|
+
};
|
|
717
746
|
let value_component = if jackson {
|
|
718
|
-
format!(
|
|
747
|
+
format!(
|
|
748
|
+
"{bean_prefix}@JsonValue @JacksonXmlText {} value",
|
|
749
|
+
base_type
|
|
750
|
+
)
|
|
719
751
|
} else {
|
|
720
|
-
format!("{} value", base_type)
|
|
752
|
+
format!("{bean_prefix}{} value", base_type)
|
|
721
753
|
};
|
|
722
754
|
|
|
723
755
|
if checks.is_empty() && !jackson {
|
|
@@ -758,6 +790,124 @@ impl JavaCodegen {
|
|
|
758
790
|
let _ = writeln!(out, "{}}}", indent);
|
|
759
791
|
}
|
|
760
792
|
|
|
793
|
+
fn bean_annotations(&self, field: &crate::ir::FieldDef) -> Vec<String> {
|
|
794
|
+
if !self.options.bean_validation {
|
|
795
|
+
return Vec::new();
|
|
796
|
+
}
|
|
797
|
+
let mut annotations = Vec::new();
|
|
798
|
+
let is_list = field.cardinality.is_list() || field.type_ref.is_list();
|
|
799
|
+
let is_optional = field.cardinality.is_optional() || field.nillable;
|
|
800
|
+
if !is_optional
|
|
801
|
+
&& !matches!(
|
|
802
|
+
self.field_type(field).as_str(),
|
|
803
|
+
"boolean" | "byte" | "short" | "int" | "long" | "float" | "double"
|
|
804
|
+
)
|
|
805
|
+
{
|
|
806
|
+
// Java primitive fields cannot be null; reference fields can.
|
|
807
|
+
annotations.push("@NotNull".to_string());
|
|
808
|
+
}
|
|
809
|
+
if matches!(&field.type_ref, TypeRef::Named(_) | TypeRef::List(_)) {
|
|
810
|
+
annotations.push("@jakarta.validation.Valid".to_string());
|
|
811
|
+
}
|
|
812
|
+
let facets = field.facets.as_ref();
|
|
813
|
+
let Some(facets) = facets else {
|
|
814
|
+
return annotations;
|
|
815
|
+
};
|
|
816
|
+
let primitive = &field.type_ref;
|
|
817
|
+
let is_string = matches!(
|
|
818
|
+
primitive,
|
|
819
|
+
TypeRef::Primitive(
|
|
820
|
+
PrimitiveType::String
|
|
821
|
+
| PrimitiveType::NormalizedString
|
|
822
|
+
| PrimitiveType::Token
|
|
823
|
+
| PrimitiveType::Name
|
|
824
|
+
| PrimitiveType::NCName
|
|
825
|
+
| PrimitiveType::QName
|
|
826
|
+
| PrimitiveType::Language
|
|
827
|
+
| PrimitiveType::NMTOKEN
|
|
828
|
+
| PrimitiveType::NMTOKENS
|
|
829
|
+
| PrimitiveType::AnyUri
|
|
830
|
+
| PrimitiveType::Id
|
|
831
|
+
| PrimitiveType::IdRef
|
|
832
|
+
| PrimitiveType::IdRefs
|
|
833
|
+
| PrimitiveType::Entity
|
|
834
|
+
| PrimitiveType::Entities
|
|
835
|
+
)
|
|
836
|
+
);
|
|
837
|
+
let is_numeric = matches!(
|
|
838
|
+
primitive,
|
|
839
|
+
TypeRef::Primitive(
|
|
840
|
+
PrimitiveType::Byte
|
|
841
|
+
| PrimitiveType::Short
|
|
842
|
+
| PrimitiveType::Int
|
|
843
|
+
| PrimitiveType::Integer
|
|
844
|
+
| PrimitiveType::Long
|
|
845
|
+
| PrimitiveType::Decimal
|
|
846
|
+
| PrimitiveType::UnsignedByte
|
|
847
|
+
| PrimitiveType::UnsignedShort
|
|
848
|
+
| PrimitiveType::UnsignedInt
|
|
849
|
+
| PrimitiveType::UnsignedLong
|
|
850
|
+
| PrimitiveType::PositiveInteger
|
|
851
|
+
| PrimitiveType::NegativeInteger
|
|
852
|
+
| PrimitiveType::NonPositiveInteger
|
|
853
|
+
| PrimitiveType::NonNegativeInteger
|
|
854
|
+
| PrimitiveType::Float
|
|
855
|
+
| PrimitiveType::Double
|
|
856
|
+
)
|
|
857
|
+
);
|
|
858
|
+
if is_list || (is_string && !is_optional) {
|
|
859
|
+
if let Some(length) = facets.length {
|
|
860
|
+
annotations.push(format!("@Size(min = {length}, max = {length})"));
|
|
861
|
+
} else if facets.min_length.is_some() || facets.max_length.is_some() {
|
|
862
|
+
annotations.push(format!(
|
|
863
|
+
"@Size(min = {}, max = {})",
|
|
864
|
+
facets.min_length.unwrap_or(0),
|
|
865
|
+
facets.max_length.unwrap_or(i32::MAX as usize)
|
|
866
|
+
));
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
if is_string && !is_optional {
|
|
870
|
+
for pattern in &facets.patterns {
|
|
871
|
+
annotations.push(format!(
|
|
872
|
+
"@jakarta.validation.constraints.Pattern(regexp = {pattern:?})"
|
|
873
|
+
));
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
if is_numeric
|
|
877
|
+
&& !is_list
|
|
878
|
+
&& !is_optional
|
|
879
|
+
&& !matches!(
|
|
880
|
+
primitive,
|
|
881
|
+
TypeRef::Primitive(PrimitiveType::Float | PrimitiveType::Double)
|
|
882
|
+
)
|
|
883
|
+
{
|
|
884
|
+
for (value, minimum, inclusive) in [
|
|
885
|
+
(facets.min_inclusive.as_ref(), true, true),
|
|
886
|
+
(facets.max_inclusive.as_ref(), false, true),
|
|
887
|
+
(facets.min_exclusive.as_ref(), true, false),
|
|
888
|
+
(facets.max_exclusive.as_ref(), false, false),
|
|
889
|
+
] {
|
|
890
|
+
if let Some(value) = value {
|
|
891
|
+
if inclusive && !matches!(primitive, TypeRef::Primitive(PrimitiveType::Decimal))
|
|
892
|
+
{
|
|
893
|
+
if let Ok(integer) = value.parse::<i64>() {
|
|
894
|
+
annotations.push(format!(
|
|
895
|
+
"@{}({integer})",
|
|
896
|
+
if minimum { "Min" } else { "Max" }
|
|
897
|
+
));
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
let annotation = if minimum { "DecimalMin" } else { "DecimalMax" };
|
|
902
|
+
annotations.push(format!(
|
|
903
|
+
"@{annotation}(value = {value:?}, inclusive = {inclusive})"
|
|
904
|
+
));
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
annotations
|
|
909
|
+
}
|
|
910
|
+
|
|
761
911
|
fn build_facet_checks(
|
|
762
912
|
&self,
|
|
763
913
|
var_name: &str,
|
|
@@ -16,6 +16,13 @@ impl JavaCodegen {
|
|
|
16
16
|
let implements = interface.map(|v| format!(", {v}")).unwrap_or_default();
|
|
17
17
|
let ty_name = self.context.map_type_ref(ty);
|
|
18
18
|
let _ = writeln!(out, "{indent}public {nested}final class {name} implements java.io.Serializable{implements} {{\n{indent} private static final long serialVersionUID = 1L;");
|
|
19
|
+
if self.options.bean_validation {
|
|
20
|
+
let mut value_field = FieldDef::new("value", "value", FieldKind::Text, ty.clone());
|
|
21
|
+
value_field.facets = facets.cloned();
|
|
22
|
+
for annotation in self.bean_annotations(&value_field) {
|
|
23
|
+
let _ = writeln!(out, "{indent} {annotation}");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
19
26
|
if self.options.backend.is_jackson() {
|
|
20
27
|
let _ = writeln!(out, "{indent} @JsonValue @JacksonXmlText");
|
|
21
28
|
}
|
|
@@ -153,6 +160,9 @@ impl JavaCodegen {
|
|
|
153
160
|
let own = &fields[fields.len() - s.fields.len()..];
|
|
154
161
|
for (f, id) in own {
|
|
155
162
|
self.emit_property_annotations(out, f, &format!("{indent} "));
|
|
163
|
+
for annotation in self.bean_annotations(f) {
|
|
164
|
+
let _ = writeln!(out, "{indent} {annotation}");
|
|
165
|
+
}
|
|
156
166
|
let _ = writeln!(
|
|
157
167
|
out,
|
|
158
168
|
"{indent} private {} {id} = {};",
|
|
@@ -355,6 +355,14 @@ impl XmlDeserializer {
|
|
|
355
355
|
}
|
|
356
356
|
}
|
|
357
357
|
ValueType::Nested(sub_schema) => {
|
|
358
|
+
if is_nil {
|
|
359
|
+
stack
|
|
360
|
+
.last_mut()
|
|
361
|
+
.unwrap()
|
|
362
|
+
.push_list_item(field_idx, PolyValue::Null);
|
|
363
|
+
unknown_depth = 1;
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
358
366
|
let frame_schema = resolve_record_schema(
|
|
359
367
|
sub_schema,
|
|
360
368
|
e,
|
|
@@ -367,6 +375,12 @@ impl XmlDeserializer {
|
|
|
367
375
|
_ => {}
|
|
368
376
|
},
|
|
369
377
|
ValueType::Nested(sub_schema) => {
|
|
378
|
+
if is_nil {
|
|
379
|
+
stack.last_mut().unwrap().values[field_idx] =
|
|
380
|
+
Some(PolyValue::Null);
|
|
381
|
+
unknown_depth = 1;
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
370
384
|
let frame_schema = resolve_record_schema(
|
|
371
385
|
sub_schema,
|
|
372
386
|
e,
|
|
@@ -414,6 +428,13 @@ impl XmlDeserializer {
|
|
|
414
428
|
stack.last_mut().unwrap().push_list_item(field_idx, val);
|
|
415
429
|
}
|
|
416
430
|
ValueType::Nested(sub_schema) => {
|
|
431
|
+
if is_nil {
|
|
432
|
+
stack
|
|
433
|
+
.last_mut()
|
|
434
|
+
.unwrap()
|
|
435
|
+
.push_list_item(field_idx, PolyValue::Null);
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
417
438
|
let frame_schema =
|
|
418
439
|
resolve_record_schema(sub_schema, e, &scope)?;
|
|
419
440
|
let mut frame = StackFrame::new(frame_schema);
|
|
@@ -427,6 +448,11 @@ impl XmlDeserializer {
|
|
|
427
448
|
_ => {}
|
|
428
449
|
},
|
|
429
450
|
ValueType::Nested(sub_schema) => {
|
|
451
|
+
if is_nil {
|
|
452
|
+
stack.last_mut().unwrap().values[field_idx] =
|
|
453
|
+
Some(PolyValue::Null);
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
430
456
|
let frame_schema = resolve_record_schema(sub_schema, e, &scope)?;
|
|
431
457
|
let mut frame = StackFrame::new(frame_schema);
|
|
432
458
|
Self::parse_attributes(e, &mut frame)?;
|
|
@@ -159,6 +159,7 @@ fn test_java_records_and_enums_generation() {
|
|
|
159
159
|
emit_builder: false,
|
|
160
160
|
emit_direct_codec: false,
|
|
161
161
|
validate_facets: true,
|
|
162
|
+
bean_validation: false,
|
|
162
163
|
emit_root_aliases: true,
|
|
163
164
|
custom_header: None,
|
|
164
165
|
};
|
|
@@ -249,6 +250,7 @@ fn test_java_sealed_interface_choice() {
|
|
|
249
250
|
emit_builder: false,
|
|
250
251
|
emit_direct_codec: false,
|
|
251
252
|
validate_facets: true,
|
|
253
|
+
bean_validation: false,
|
|
252
254
|
emit_root_aliases: true,
|
|
253
255
|
custom_header: None,
|
|
254
256
|
};
|
|
@@ -305,6 +307,7 @@ fn test_java_module_container_class() {
|
|
|
305
307
|
emit_builder: false,
|
|
306
308
|
emit_direct_codec: false,
|
|
307
309
|
validate_facets: true,
|
|
310
|
+
bean_validation: false,
|
|
308
311
|
emit_root_aliases: true,
|
|
309
312
|
custom_header: None,
|
|
310
313
|
};
|
|
@@ -417,6 +420,7 @@ fn test_java_jackson_backend_struct_annotations() {
|
|
|
417
420
|
emit_builder: false,
|
|
418
421
|
emit_direct_codec: false,
|
|
419
422
|
validate_facets: true,
|
|
423
|
+
bean_validation: false,
|
|
420
424
|
emit_root_aliases: true,
|
|
421
425
|
custom_header: None,
|
|
422
426
|
};
|
|
@@ -480,6 +484,7 @@ fn test_java_jackson_backend_enum_annotations() {
|
|
|
480
484
|
emit_builder: false,
|
|
481
485
|
emit_direct_codec: false,
|
|
482
486
|
validate_facets: true,
|
|
487
|
+
bean_validation: false,
|
|
483
488
|
emit_root_aliases: true,
|
|
484
489
|
custom_header: None,
|
|
485
490
|
};
|
|
@@ -530,6 +535,7 @@ fn test_java_jackson_backend_union_annotations() {
|
|
|
530
535
|
emit_builder: false,
|
|
531
536
|
emit_direct_codec: false,
|
|
532
537
|
validate_facets: true,
|
|
538
|
+
bean_validation: false,
|
|
533
539
|
emit_root_aliases: true,
|
|
534
540
|
custom_header: None,
|
|
535
541
|
};
|
|
@@ -574,6 +580,7 @@ fn test_java_jackson_backend_simple_type_annotations() {
|
|
|
574
580
|
emit_builder: false,
|
|
575
581
|
emit_direct_codec: false,
|
|
576
582
|
validate_facets: true,
|
|
583
|
+
bean_validation: false,
|
|
577
584
|
emit_root_aliases: true,
|
|
578
585
|
custom_header: None,
|
|
579
586
|
};
|
|
@@ -628,6 +635,55 @@ fn test_java_jackson_backend_from_str_loose() {
|
|
|
628
635
|
assert_eq!(JavaBackend::from_str_loose("unknown"), None);
|
|
629
636
|
}
|
|
630
637
|
|
|
638
|
+
#[test]
|
|
639
|
+
fn test_java_bean_validation_annotations_are_opt_in() {
|
|
640
|
+
let schema = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
641
|
+
<xs:simpleType name="Code"><xs:restriction base="xs:string">
|
|
642
|
+
<xs:minLength value="2"/><xs:maxLength value="8"/><xs:pattern value="[A-Z]+"/>
|
|
643
|
+
</xs:restriction></xs:simpleType>
|
|
644
|
+
<xs:simpleType name="Count"><xs:restriction base="xs:int">
|
|
645
|
+
<xs:minInclusive value="1"/><xs:maxInclusive value="10"/>
|
|
646
|
+
</xs:restriction></xs:simpleType>
|
|
647
|
+
<xs:simpleType name="Price"><xs:restriction base="xs:decimal">
|
|
648
|
+
<xs:minExclusive value="0.0"/><xs:maxExclusive value="99.9"/>
|
|
649
|
+
</xs:restriction></xs:simpleType>
|
|
650
|
+
<xs:complexType name="Order"><xs:sequence>
|
|
651
|
+
<xs:element name="code" type="Code"/>
|
|
652
|
+
<xs:element name="count" type="Count"/>
|
|
653
|
+
<xs:element name="price" type="Price"/>
|
|
654
|
+
</xs:sequence></xs:complexType>
|
|
655
|
+
</xs:schema>"#;
|
|
656
|
+
let ir = polyxml::schema_parser::XsdParser::new()
|
|
657
|
+
.parse_str(schema)
|
|
658
|
+
.unwrap();
|
|
659
|
+
let plain = JavaCodegen::new(JavaOptions::default()).generate_files(&ir);
|
|
660
|
+
assert!(plain
|
|
661
|
+
.iter()
|
|
662
|
+
.all(|(_, code)| !code.contains("jakarta.validation")));
|
|
663
|
+
let files = JavaCodegen::new(JavaOptions {
|
|
664
|
+
bean_validation: true,
|
|
665
|
+
..Default::default()
|
|
666
|
+
})
|
|
667
|
+
.generate_files(&ir);
|
|
668
|
+
let source = |name: &str| {
|
|
669
|
+
files
|
|
670
|
+
.iter()
|
|
671
|
+
.find(|(file, _)| file == name)
|
|
672
|
+
.unwrap()
|
|
673
|
+
.1
|
|
674
|
+
.as_str()
|
|
675
|
+
};
|
|
676
|
+
assert!(source("Code.java").contains("@Size(min = 2, max = 8)"));
|
|
677
|
+
assert!(source("Code.java")
|
|
678
|
+
.contains("@jakarta.validation.constraints.Pattern(regexp = \"[A-Z]+\")"));
|
|
679
|
+
assert!(source("Count.java").contains("@Min(1)"));
|
|
680
|
+
assert!(source("Count.java").contains("@Max(10)"));
|
|
681
|
+
assert!(source("Price.java").contains("@DecimalMin(value = \"0.0\", inclusive = false)"));
|
|
682
|
+
assert!(source("Price.java").contains("@DecimalMax(value = \"99.9\", inclusive = false)"));
|
|
683
|
+
assert!(source("Order.java").contains("@NotNull"));
|
|
684
|
+
assert!(source("Order.java").contains("@jakarta.validation.Valid"));
|
|
685
|
+
}
|
|
686
|
+
|
|
631
687
|
#[test]
|
|
632
688
|
fn test_java_mutable_builders_and_direct_codecs_execute() {
|
|
633
689
|
let schema = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
@@ -42,9 +42,9 @@ const VEHICLE_XSD: &str = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSche
|
|
|
42
42
|
<xs:element name="Root">
|
|
43
43
|
<xs:complexType>
|
|
44
44
|
<xs:sequence>
|
|
45
|
-
<xs:element name="vehicle" type="t:Vehicle"/>
|
|
45
|
+
<xs:element name="vehicle" type="t:Vehicle" nillable="true"/>
|
|
46
46
|
<xs:element name="spare" type="t:Vehicle"
|
|
47
|
-
minOccurs="0" maxOccurs="unbounded"/>
|
|
47
|
+
minOccurs="0" maxOccurs="unbounded" nillable="true"/>
|
|
48
48
|
</xs:sequence>
|
|
49
49
|
</xs:complexType>
|
|
50
50
|
</xs:element>
|
|
@@ -330,6 +330,19 @@ fn abstract_type_requires_concrete_selector() {
|
|
|
330
330
|
}
|
|
331
331
|
}
|
|
332
332
|
|
|
333
|
+
#[test]
|
|
334
|
+
fn nil_abstract_complex_type_skips_concrete_dispatch() {
|
|
335
|
+
let root = schema_for(Some("Root"));
|
|
336
|
+
for xml in [
|
|
337
|
+
br#"<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><vehicle xsi:nil="true"/><spare xsi:nil="true"/></Root>"#.as_slice(),
|
|
338
|
+
br#"<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><vehicle xsi:nil="true"></vehicle><spare xsi:nil="true"></spare></Root>"#.as_slice(),
|
|
339
|
+
] {
|
|
340
|
+
let value = polyxml::deserialize(xml, Arc::clone(&root)).expect("nil abstract field");
|
|
341
|
+
assert!(matches!(rec_field(&value, "vehicle"), Some(PolyValue::Null)));
|
|
342
|
+
assert!(matches!(rec_field(&value, "spare"), Some(PolyValue::List(items)) if matches!(items.as_slice(), [PolyValue::Null])));
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
333
346
|
#[test]
|
|
334
347
|
fn xsi_type_resolves_namespace_inherited_from_parent() {
|
|
335
348
|
let root = schema_for(Some("Root"));
|
|
@@ -58,6 +58,17 @@ class Fleet:
|
|
|
58
58
|
)
|
|
59
59
|
|
|
60
60
|
|
|
61
|
+
@dataclass
|
|
62
|
+
class NullableFleet:
|
|
63
|
+
class Meta:
|
|
64
|
+
name = "Fleet"
|
|
65
|
+
|
|
66
|
+
vehicle: Vehicle | None = field(
|
|
67
|
+
default=None,
|
|
68
|
+
metadata={"type": "Element", "name": "vehicle", "nillable": True},
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
61
72
|
@dataclass
|
|
62
73
|
class LonelyBase:
|
|
63
74
|
class Meta:
|
|
@@ -85,6 +96,14 @@ FLEET_XML = (
|
|
|
85
96
|
)
|
|
86
97
|
|
|
87
98
|
|
|
99
|
+
def test_nil_abstract_complex_type_without_selector():
|
|
100
|
+
xml = (
|
|
101
|
+
b'<Fleet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
|
102
|
+
b'<vehicle xsi:nil="true"/></Fleet>'
|
|
103
|
+
)
|
|
104
|
+
assert polyxml.deserialize(xml, NullableFleet).vehicle is None
|
|
105
|
+
|
|
106
|
+
|
|
88
107
|
def make_fleet() -> Fleet:
|
|
89
108
|
return Fleet(
|
|
90
109
|
vehicle=Car(id="V1", doors=4),
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polyxml-0.25.0 → polyxml-0.26.0}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|