1

From C# I'm calling RESTful web service that returns JSON. The service can return an arbitrary Javascript object, we don't know its structure at compile time.

Usually, it returns a JSON object, but there are situations where it returns a simple string. JSON.Net throws a runtime error when I try to deserialize the simple string.

dynamic dyn = JsonConvert.DeserializeObject("just a string");            

throws:

Newtonsoft.Json.JsonReaderException was unhandled by user code
  HResult=-2146233088
  Message=Unexpected character encountered while parsing value: j. Path '', line 0, position 0.

I read the answers to Is this simple string considered valid JSON? and the consensus seems to be that returning a simple string as JSON is legal, but many implementations don't yet support this.

Is this true for JSON.NET? What are the workarounds to handle deserializing JSON that might contain simple types and not just objects and arrays?

This seems to work fine, am I missing something?

dynamic dyn;

dyn = GetObjectFromJSON("{ \"name\": \"john\", \"age\": 32 }");
Debug.WriteLine((string)Convert.ToString(dyn));

dyn = GetObjectFromJSON("[ \"a\", \"b\", \"c\" ]");
Debug.WriteLine((string)Convert.ToString(dyn));

dyn = GetObjectFromJSON("just a string");
Debug.WriteLine((string)Convert.ToString(dyn));

dyn = GetObjectFromJSON("35");
Debug.WriteLine((string)Convert.ToString(dyn));

dyn = GetObjectFromJSON("true");
Debug.WriteLine((string)Convert.ToString(dyn));

dyn = GetObjectFromJSON(null);
Debug.WriteLine((Object)dyn ?? "(null)");

and

private Object GetObjectFromJSON(string jsonString)
{
    if (String.IsNullOrEmpty(jsonString))
    {
        return null;
    }

    dynamic jsonResponse;
    jsonString = jsonString.Trim();
    if (jsonString.StartsWith("{") || jsonString.StartsWith("["))
    {
        // object or array
        jsonResponse = JsonConvert.DeserializeObject(jsonString);
    }
    else
    {
        // some literal value
        double d;
        bool b;
        if (Double.TryParse(jsonString, out d))
        {
            return d;
        }
        else if (bool.TryParse(jsonString, out b))
        {
            return b;
        }
        else
        {
            // not null, not an object, not an array, not a number, and not  a boolean, so it's a string
            jsonResponse = jsonString;
        }
    }
    return jsonResponse;
}
Michael Levy
  • 13,097
  • 15
  • 66
  • 100
  • 3
    I believe you think `dynamic dyn = JsonConvert.DeserializeObject("just a string");` is passing in a string, but it is not. Try `dynamic dyn = JsonConvert.DeserializeObject("\"just a string\"");` and see what the result is :) Check out the [json spec](http://www.json.org/) for more details. – afuzzyllama Oct 02 '17 at 21:44
  • yes, i see. Do you want to post as an answer? This then raises a different question. It seems that the web service should return the quoted string in the http body, but there are no double quotes in the response. – Michael Levy Oct 02 '17 at 22:08
  • 1
    Are you sure the web service is returning type JSON and not plain text? – afuzzyllama Oct 02 '17 at 22:10
  • Yes, it is returning JSON. I'll post a different question asking why Java/Jersey doesn't seem to quote simple string JSON responses. – Michael Levy Oct 02 '17 at 23:19
  • FYI, https://stackoverflow.com/questions/46535586/java-jersey-json-service-doesnt-return-quoted-string – Michael Levy Oct 03 '17 at 00:33

2 Answers2

0

@afuzzyllama set me straight in the comments (if he posts an answer, I'll happily accept it!).

dynamic dyn = JsonConvert.DeserializeObject("just a string");           

fails because the string is not valid JSON. Strings must be quoted, so to be correct this should be:

dynamic dyn = JsonConvert.DeserializeObject("\"just a string\"");           

For more info, see http://www.json.org/

But, this is apparently the accepted (and by design behavior) of JAX-RS/Jersey web services returning simple strings. See https://stackoverflow.com/a/46535680/90236

Michael Levy
  • 13,097
  • 15
  • 66
  • 100
0

Looking at the following call:

dynamic dyn = JsonConvert.DeserializeObject("just a string");           

This isn't deserializing "just a string" it is deserializing just a string (notice the string is surrounded by "").

If we look at the spec for JSON, the only valid alpha character sequences that are not bounded by "" are true, false, and null.

If we want to deserialize a string, we need to make sure it is a valid string as defined by the spec. This should be a valid deserialization call:

dynamic dyn = JsonConvert.DeserializeObject("\"just a string\"");           

Looking at your previous question Java Jersey JSON service doesn't return quoted string?, I noticed you are returning an Object type:

@GET
@Produces(MediaType.APPLICATION_JSON)
public Object interpretationJson() {                        
    String o = "a simple string";       
    return o;
}

I do not have any experience with Jersey, but perhaps the framework has trouble interpreting the generic Object. Perhaps if you used a String return type the results would be different? From the accepted answer from that question it does not seem to be the case?

Maybe a solution like the following, adding the "" and changing the return type, would be appropriate?

@GET
@Produces(MediaType.APPLICATION_JSON)
public String interpretationJson() {                        
    String o = "\"a simple string\"";       
    return o;
}

The result of that should be deserializable.

afuzzyllama
  • 6,538
  • 5
  • 47
  • 64