Skip to content

Commit 7467c5b

Browse files
Merge pull request #158 from gabriel-samfira/fix-wrapped-objects
Fix serialization of PSCustomObject wrapped object
2 parents 5d3ecb4 + e5b7b1a commit 7467c5b

File tree

4 files changed

+98
-2
lines changed

4 files changed

+98
-2
lines changed

Tests/powershell-yaml.Tests.ps1

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,52 @@ Import-Module $modulePath
2828
InModuleScope $moduleName {
2929
$compareStrictly = Get-EquivalencyOption -Comparator Equality
3030

31+
Describe "Test PSCustomObject wrapped values are serialized correctly" {
32+
Context "A PSCustomObject containing nested PSCustomObjects" {
33+
It "Should serialize correctly" {
34+
$expectBigInt = [System.Numerics.BigInteger]::Parse("9999999999999999999999999999999999999999999999999")
35+
$obj = [PSCustomObject]@{a = Write-Output 'string'; b = Write-Output 1; c = Write-Output @{nested = $true};d = [pscustomobject]$expectBigInt}
36+
$asYaml = ConvertTo-Yaml $obj
37+
$fromYaml = ConvertFrom-Yaml $asYaml
38+
39+
Assert-Equivalent -Options $compareStrictly -Expected "string" -Actual $fromYaml["a"]
40+
Assert-Equivalent -Options $compareStrictly -Expected 1 -Actual $fromYaml["b"]
41+
Assert-Equivalent -Options $compareStrictly -Expected $expectBigInt -Actual $fromYaml["d"]
42+
}
43+
}
44+
45+
Context "A hashtable containing nested PSCustomObjects" {
46+
It "Should serialize correctly" {
47+
$expectBigInt = [System.Numerics.BigInteger]::Parse("9999999999999999999999999999999999999999999999999")
48+
$obj = @{a = Write-Output 'string'; b = Write-Output 1; c = Write-Output @{nested = $true};d = [pscustomobject]$expectBigInt}
49+
$asYaml = ConvertTo-Yaml $obj
50+
$fromYaml = ConvertFrom-Yaml $asYaml
51+
52+
Assert-Equivalent -Options $compareStrictly -Expected "string" -Actual $fromYaml["a"]
53+
Assert-Equivalent -Options $compareStrictly -Expected 1 -Actual $fromYaml["b"]
54+
Assert-Equivalent -Options $compareStrictly -Expected $expectBigInt -Actual $fromYaml["d"]
55+
}
56+
}
57+
58+
Context "A generic dictionary containing nested PSCustomObjects" {
59+
It "Should serialize correctly" {
60+
$expectBigInt = [System.Numerics.BigInteger]::Parse("9999999999999999999999999999999999999999999999999")
61+
$obj = [System.Collections.Generic.Dictionary[string, object]]::new()
62+
$obj["a"] = Write-Output 'string'
63+
$obj["b"] = Write-Output 1
64+
$obj["c"] = Write-Output @{nested = $true}
65+
$obj["d"] = [pscustomobject]$expectBigInt
66+
67+
$asYaml = ConvertTo-Yaml $obj
68+
$fromYaml = ConvertFrom-Yaml $asYaml
69+
70+
Assert-Equivalent -Options $compareStrictly -Expected "string" -Actual $fromYaml["a"]
71+
Assert-Equivalent -Options $compareStrictly -Expected 1 -Actual $fromYaml["b"]
72+
Assert-Equivalent -Options $compareStrictly -Expected $expectBigInt -Actual $fromYaml["d"]
73+
}
74+
}
75+
}
76+
3177
Describe "Test encode-decode symmetry." {
3278

3379
Context "Simple-Items" {
512 Bytes
Binary file not shown.
512 Bytes
Binary file not shown.

src/PowerShellYamlSerializer.cs

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,46 @@ public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerialize
4949
}
5050
}
5151

52+
public class IDictionaryTypeConverter : IYamlTypeConverter {
53+
54+
private bool omitNullValues;
55+
56+
public IDictionaryTypeConverter(bool omitNullValues = false) {
57+
this.omitNullValues = omitNullValues;
58+
}
59+
60+
public bool Accepts(Type type) {
61+
return typeof(IDictionary).IsAssignableFrom(type);
62+
}
63+
64+
public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) {
65+
var deserializedObject = rootDeserializer(typeof(IDictionary<string, object>)) as IDictionary;
66+
return deserializedObject;
67+
}
68+
69+
public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer) {
70+
var hObj = (IDictionary)value;
71+
emitter.Emit(new MappingStart());
72+
foreach (DictionaryEntry entry in hObj) {
73+
if(entry.Value == null) {
74+
if (this.omitNullValues == true) {
75+
continue;
76+
}
77+
serializer(entry.Key, entry.Key.GetType());
78+
emitter.Emit(new Scalar(AnchorName.Empty, "tag:yaml.org,2002:null", "", ScalarStyle.Plain, true, false));
79+
continue;
80+
}
81+
serializer(entry.Key, entry.Key.GetType());
82+
if (entry.Value is PSObject nestedObj) {
83+
serializer(nestedObj.BaseObject, nestedObj.BaseObject.GetType());
84+
} else {
85+
serializer(entry.Value, entry.Value.GetType());
86+
}
87+
}
88+
emitter.Emit(new MappingEnd());
89+
}
90+
}
91+
5292
public class PSObjectTypeConverter : IYamlTypeConverter {
5393

5494
private bool omitNullValues;
@@ -70,7 +110,6 @@ public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeseria
70110

71111
public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer) {
72112
var psObj = (PSObject)value;
73-
74113
emitter.Emit(new MappingStart());
75114
foreach (var prop in psObj.Properties) {
76115
if (prop.Value == null) {
@@ -81,7 +120,17 @@ public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerialize
81120
emitter.Emit(new Scalar(AnchorName.Empty, "tag:yaml.org,2002:null", "", ScalarStyle.Plain, true, false));
82121
} else {
83122
serializer(prop.Name, prop.Name.GetType());
84-
serializer(prop.Value, prop.Value.GetType());
123+
var objType = prop.Value.GetType();
124+
var val = prop.Value;
125+
if (prop.Value is PSObject nestedPsObj) {
126+
var nestedType = nestedPsObj.BaseObject.GetType();
127+
if (nestedType != typeof(System.Management.Automation.PSCustomObject)) {
128+
objType = nestedPsObj.BaseObject.GetType();
129+
val = nestedPsObj.BaseObject;
130+
}
131+
}
132+
serializer(val, objType);
133+
85134
}
86135
}
87136
emitter.Emit(new MappingEnd());
@@ -151,6 +200,7 @@ public static SerializerBuilder BuildSerializer(
151200
builder = builder
152201
.WithEventEmitter(next => new StringQuotingEmitter(next))
153202
.WithTypeConverter(new BigIntegerTypeConverter())
203+
.WithTypeConverter(new IDictionaryTypeConverter(omitNullValues))
154204
.WithTypeConverter(new PSObjectTypeConverter(omitNullValues));
155205
if (omitNullValues == true) {
156206
builder = builder

0 commit comments

Comments
 (0)