Make ConvertFrom-Json deserialize an array of objects with multiple lines. (#3823)

* Fixing ConvertFrom-Json on CoreCLR to be able to handle a collection of strings which represent a JSON content.

* Adding test case for ConvertFrom-Json to process an array of PSObjects as a single string.
This commit is contained in:
Francisco Gamino 2017-05-25 13:00:51 -07:00 committed by Travis Plunk
parent 40446c80a7
commit 7aa7f3858c
3 changed files with 43 additions and 3 deletions

View file

@ -72,8 +72,8 @@ namespace Microsoft.PowerShell.Commands
protected override void EndProcessing()
{
// When Input is provided through pipeline, the input can be represented in the following two ways:
// 1. Each input to the buffer is a complete Json content. There can be multiple inputs of this format.
// 2. The complete buffer input collectively represent a single JSon format. This is typically the majority of the case.
// 1. Each input in the collection is a complete Json content. There can be multiple inputs of this format.
// 2. The complete input is a collection which represents a single Json content. This is typically the majority of the case.
if (_inputObjectBuffer.Count > 0)
{
if (_inputObjectBuffer.Count == 1)
@ -85,6 +85,7 @@ namespace Microsoft.PowerShell.Commands
bool successfullyConverted = false;
try
{
// Try to deserialize the first element.
successfullyConverted = ConvertFromJsonHelper(_inputObjectBuffer[0]);
}
catch (ArgumentException)
@ -102,6 +103,7 @@ namespace Microsoft.PowerShell.Commands
}
else
{
// Process the entire input as a single Json content.
ConvertFromJsonHelper(string.Join(System.Environment.NewLine, _inputObjectBuffer.ToArray()));
}
}

View file

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
using System.Management.Automation;
using System.Text.RegularExpressions;
#if CORECLR
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@ -42,11 +43,28 @@ namespace Microsoft.PowerShell.Commands
{
throw new ArgumentNullException("input");
}
error = null;
#if CORECLR
object obj = null;
try
{
// JsonConvert.DeserializeObject does not throw an exception when an invalid Json array is passed.
// This issue is being tracked by https://github.com/JamesNK/Newtonsoft.Json/issues/1321.
// To work around this, we need to identify when input is a Json array, and then try to parse it via JArray.Parse().
// If input starts with '[' or ends with ']' (ignoring white spaces).
if ((Regex.Match(input, @"(^\s*\[)|(\s*\]$)")).Success)
{
// JArray.Parse() will throw a JsonException if the array is invalid.
// This will be caught by the catch block below, and then throw an
// ArgumentException - this is done to have same behavior as the JavaScriptSerializer.
JArray.Parse(input);
// Please note that if the Json array is valid, we don't do anything,
// we just continue the deserialization.
}
obj = JsonConvert.DeserializeObject(input, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.None, MaxDepth = 1024 });
// JObject is a IDictionary

View file

@ -228,7 +228,6 @@ Describe "Json Tests" -Tags "Feature" {
# add a ScriptProperty called IsOld which returns whether the version is an older version
$versionObject | Add-Member -MemberType ScriptProperty -Name IsOld -Value { ($this.Major -le 3) }
$jstr = ConvertTo-Json $versionObject
# convert the JSON string to a JSON object
@ -1455,4 +1454,25 @@ Describe "Json Bug fixes" -Tags "Feature" {
{
RunJsonTest $testCase
}
It "ConvertFrom-Json deserializes an array of PSObjects (in multiple lines) as a single string." {
# Create an array of PSCustomObjects, and serialize it
$array = [pscustomobject]@{ objectName = "object1Name"; objectValue = "object1Value" },
[pscustomobject]@{ objectName = "object2Name"; objectValue = "object2Value" }
# Serialize the array to a text file
$filePath = Join-Path $TESTDRIVE test.json
$array | ConvertTo-Json | Out-File $filePath -Encoding utf8
# Read the object as an array of PSObjects and deserialize it.
$result = Get-Content $filePath | ConvertFrom-Json
$result.Count | Should be 2
}
It "ConvertFrom-Json deserializes an array of strings (in multiple lines) as a single string." {
$result = "[1,","2,","3]" | ConvertFrom-Json
$result.Count | Should be 3
}
}