deserialize null in json to value in c# - json

I'm working in project using ASP.net core Api
I have a case which I need to distinguish between undefined variable and null in json .
what I have is that I'm working with Api with put method , so I have json in the body as resource with 2 optional parameter like that
{"bio" : "value ,
"img" : "value}
now in the following case :
{"bio :Null}
my program in c#(deserialize from json to c# obj) will consider bio as null and image as null
public async Task<IActionResult> UpdateCurrentUser(UserForUpdateOuterDto
userForUpdateOuter)
{
//some code
var userDto = userForUpdateOuter.userForUpdateDto;
_mapper.Map<UserForUpdateDto ,User>(userDto ,currentUser);
await _userReposotory.UpdateUser(currentUser); }
//auto mapper :
//for update with Null values .if value is Null then don't map it
CreateMap<UserForUpdateDto ,User>().ForAllMembers(x => x.Condition(
(src ,dest ,sourceValue) => sourceValue != null));
BUT in reality its not the same
so is there away to deserialize null to different value (I read about that but couldn't found )?
or any other ideas
(I can't use patch coz I'm following spec )

Related

Handle JSON With null Inside Array With Kotlin

I am trying to handle null or empty JSON value fields value which has received both JSON case:
{
"field": [
null
]
}
and
{
"field": []
}
The case when an empty array works fine for me: If I get an object with an array size of 0, it means it is empty. In the second case, when the field's value is [null], I get an array size 1 with all the elements null. That is why I check the null case with the following approach:
val deserializedJson = jacksonObjectMapper().readValue<DataSimpleClass>(theJsonAsText)
if (deserializedJson.field.size == 1 && deserializedJson.field[0] == null) {
throw Exception()
}
Is there any better or more elegant approach to check such a [null] case?
I deserialize the JSON using jacksonObjectMapper() object version 2.9.8. Also, I have created a two-data class that looks like that:
#JsonInclude(JsonInclude.Include.NON_NULL)
data class DataSimpleClass(
#JsonInclude(JsonInclude.Include.NON_NULL)
val field: List<SpecificClass>
)
#JsonInclude(JsonInclude.Include.NON_NULL)
data class SpecificClass(
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonProperty("field1") val field1: String,
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonProperty("field2") val field2: String,
#JsonProperty("field3") val field3: String? = null,
val updateTime: Instant = Instant.now(Clock.systemUTC())
)
Also, I don't understand how Kotlin (null-safe language) may let me create a field when all the elements are null. How is it possible that Kotlin doesn't catch null while I send the non-nullable field null value The deserializedJson result, then the JSON key's value is null ?
I was expecting that the null won't be deserialized cause of its null value, as the object DataSimpleClass holds a non-nullable field.
In addition, my IntelliJ shows me that due to the null safe fields, the following condition "is always false" while, in fact, it is actually true during the run.
How is it possible that the value shouldn't be null due to the null safe, but it all gets null during the run time?the IntelliJ warning for wrong condition result
Kotlin is "null-safe" language because it enforces non-null-ability by default.
You can still have nulls in Kotlin - e.g. val foo: String? = null
The IDE just says that based on your definition it shouldn't be null and it will not allow you(at compile time) to put null there. Runtime is where don't have control over who/what puts null there.
If there is no guarantee that you will not receive null there you should sanitize it before assuming there are no nulls.
deserializedJson.field..filterNotNull()
If you would rather that it crashed the whole app I think you can set
.addModule(KotlinModule(strictNullChecks = true))
when configuring Jackson.

ZonedDateTime Custom JSON Converter Grails 3.3.0

I am in the process of converting a really old Grails app to the latest version (3.3.0). Things have been a bit frustrating, but I'm pretty close to migrating everything except the JSON and XML marshallers which were previously registered in my BootStrap init.
The previous marshaller registering looked like this:
// register JSON marshallers at startup in all environments
MarshallerUtils.registerMarshallers()
This was defined like this:
class MarshallerUtils {
// Registers marshaller logic for various types that
// aren't supported out of the box or that we want to customize.
// These are used whenever the JSON or XML converters are called,
// e.g. return model as JSON
static registerMarshallers() {
final dateTimeFormatter = ISODateTimeFormat.dateTimeNoMillis()
final isoDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
// register marshalling logic for both XML and JSON converters
[XML, JSON].each { converter ->
// This overrides the marshaller from the joda time plugin to
// force all DateTime instances to use the UTC time zone
// and the ISO standard "yyyy-mm-ddThh:mm:ssZ" format
converter.registerObjectMarshaller(DateTime, 10) { DateTime it ->
return it == null ? null : it.toString(dateTimeFormatter.withZone(org.joda.time.DateTimeZone.UTC))
}
converter.registerObjectMarshaller(Date, 10) { Date it ->
return it == null ? null : isoDateFormat.format(it)
}
converter.registerObjectMarshaller(TIMESTAMP, 10) { TIMESTAMP it ->
return it == null ? null : isoDateFormat.format(it.dateValue())
}
}
}
}
During the migration, I ended up converting all instances of org.joda.time.DateTime to java.time.ZonedDateTime:
class MarshallerUtils {
// Registers marshaller logic for various types that
// aren't supported out of the box or that we want to customize.
// These are used whenever the JSON or XML converters are called,
// e.g. return model as JSON
static registerMarshallers() {
final dateTimeFormatter = DateTimeFormatter.ISO_ZONED_DATE_TIME
final isoDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
// register marshalling logic for both XML and JSON converters
[XML, JSON].each { converter ->
// This overrides the marshaller from the java.time to
// force all DateTime instances to use the UTC time zone
// and the ISO standard "yyyy-mm-ddThh:mm:ssZ" format
converter.registerObjectMarshaller(ZonedDateTime, 10) { ZonedDateTime it ->
return it == null ? null : it.toString(dateTimeFormatter.withZone(ZoneId.of("UTC")))
}
converter.registerObjectMarshaller(Date, 10) { Date it ->
return it == null ? null : isoDateFormat.format(it)
}
converter.registerObjectMarshaller(TIMESTAMP, 10) { TIMESTAMP it ->
return it == null ? null : isoDateFormat.format(it.dateValue())
}
}
}
}
Unfortunately, after the upgrade to Grails 3.3.0, this marshaller registering doesn't seem to be used at all, no matter what I try to do.
I do know that there is a new "JSON Views" way of doing things, but this particular service has many endpoints, and I don't want to write custom converters and ".gson" templates for all of them, if everything is already in the format I need. I just need the responses to be in JSON and the dates to behave property (be formatted strings).
Instead, what I am finding (compared to the previous behavior, is that the properties which utilize ZonedDateTime are "exploded" in my JSON output. There is an insane amount of garbage date object information that is not needed, and it is not formatted as a simple string as I expect.
I have tried a few things (mostly per recommendations in the offical latest Grails documentation) ---
Custom Converters
Default Date Format
Adding configurations for grails views in application.yml:
views:
json:
generator:
dateFormat: "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
locale: "en/US"
timeZone: "GMT"
Creating this path under "src":
src/main/resources/META-INF/services/grails.plugin.json.builder.JsonGenerator$Converter
And adding a Converter to my domain class which is named in the file above^:
class MultibeamFileConverter implements JsonGenerator.Converter {
final DateTimeFormatter isoDateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").withZone(ZoneId.of("UTC"));
#Override
boolean handles(Class<?> type) {
MultibeamFile.isAssignableFrom(type)
}
#Override
Object convert(Object value, String key) {
MultibeamFile multibeamFile = (MultibeamFile)value
multibeamFile.startTime.format(isoDateFormat)
multibeamFile.endTime.format(isoDateFormat)
return multibeamFile
}
}
In my controller, I have changed:
return multibeamCatalogService.findFiles(cmd, params)
To this (in order to get JSON output in the browser as before):
respond multibeamCatalogService.findFiles(cmd, params), formats: ['json', 'xml']
Unfortuantely, most permutations I can think to try of the above have resulted in errors such as "Could not resolve view". Otherwise, when I am getting a response, the major issue is that the date is not formatted as a string. This function was previously performed by the Marshaller.
I am getting pretty frustrated. Can someone please tell me how to format ZonedDateTime as a simple string (e.g. - "2009-06-21T00:00:00Z") in my JSON output instead of a giant object like this? Simply converting to java.util.Date causes the "Could not resolve view" error to show up again; consequently, that expects me to make a ".gson" view which never ends up showing the format I expect or is empty.
"startTime": {
"dayOfMonth": 26,
"dayOfWeek": {
"enumType": "java.time.DayOfWeek",
"name": "FRIDAY"
},
"dayOfYear": 207,
"hour": 0,
"minute": 0,
"month": {
"enumType": "java.time.Month",
"name": "JULY"
},
"monthValue": 7,
"nano": 0,
"offset": {
"id": "-06:00",
"rules": {
"fixedOffset": true,
"transitionRules": [],
"transitions": []
},
"totalSeconds": -21600
}, ... // AND SO ON FOR_EVAH
The simple answer is to format a ZonedDateTime object you call .format(DateTimeFormatter). It depends what format you want. You can specify your own or use some of the predefined ones in DateTimeFormatter.
I too though would love to know if there's an easy way to say "for every endpoint display it as json". The only way I've found so far is to have this in every controller class, which isn't too bad but seems silly. I'm using respond followed by a return in my controller methods.
static responseFormats = ['json'] // This is needed for grails to indicate what format to use for respond.
Though I still see the error logged, but rest api still appears to work, "Could not resolve view" for any endpoint I hit.

Representing null in JSON

What is the preferred method for returning null values in JSON? Is there a different preference for primitives?
For example, if my object on the server has an Integer called "myCount" with no value, the most correct JSON for that value would be:
{}
or
{
"myCount": null
}
or
{
"myCount": 0
}
Same question for Strings - if I have a null string "myString" on the server, is the best JSON:
{}
or
{
"myString": null
}
or
{
"myString": ""
}
or (lord help me)
{
"myString": "null"
}
I like the convention for collections to be represented in the JSON as an empty collection http://jtechies.blogspot.nl/2012/07/item-43-return-empty-arrays-or.html
An empty Array would be represented:
{
"myArray": []
}
EDIT Summary
The 'personal preference' argument seems realistic, but short sighted in that, as a community we will be consuming an ever greater number of disparate services/sources. Conventions for JSON structure would help normalize consumption and reuse of said services. As far as establishing a standard, I would suggest adopting most of the Jackson conventions with a few exceptions:
Objects are preferred over primitives.
Empty collections are preferred over null.
Objects with no value are represented as null.
Primitives return their value.
If you are returning a JSON object with mostly null values, you may have a candidate for refactoring into multiple services.
{
"value1": null,
"value2": null,
"text1": null,
"text2": "hello",
"intValue": 0, //use primitive only if you are absolutely sure the answer is 0
"myList": [],
"myEmptyList": null, //NOT BEST PRACTICE - return [] instead
"boolean1": null, //use primitive only if you are absolutely sure the answer is true/false
"littleboolean": false
}
The above JSON was generated from the following Java class.
package jackson;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonApp {
public static class Data {
public Integer value1;
public Integer value2;
public String text1;
public String text2 = "hello";
public int intValue;
public List<Object> myList = new ArrayList<Object>();
public List<Object> myEmptyList;
public Boolean boolean1;
public boolean littleboolean;
}
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(new Data()));
}
}
Maven dependency:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.3.0</version>
</dependency>
Let's evaluate the parsing of each:
http://jsfiddle.net/brandonscript/Y2dGv/
var json1 = '{}';
var json2 = '{"myCount": null}';
var json3 = '{"myCount": 0}';
var json4 = '{"myString": ""}';
var json5 = '{"myString": "null"}';
var json6 = '{"myArray": []}';
console.log(JSON.parse(json1)); // {}
console.log(JSON.parse(json2)); // {myCount: null}
console.log(JSON.parse(json3)); // {myCount: 0}
console.log(JSON.parse(json4)); // {myString: ""}
console.log(JSON.parse(json5)); // {myString: "null"}
console.log(JSON.parse(json6)); // {myArray: []}
The tl;dr here:
The fragment in the json2 variable is the way the JSON spec indicates null should be represented. But as always, it depends on what you're doing -- sometimes the "right" way to do it doesn't always work for your situation. Use your judgement and make an informed decision.
JSON1 {}
This returns an empty object. There is no data there, and it's only going to tell you that whatever key you're looking for (be it myCount or something else) is of type undefined.
JSON2 {"myCount": null}
In this case, myCount is actually defined, albeit its value is null. This is not the same as both "not undefined and not null", and if you were testing for one condition or the other, this might succeed whereas JSON1 would fail.
This is the definitive way to represent null per the JSON spec.
JSON3 {"myCount": 0}
In this case, myCount is 0. That's not the same as null, and it's not the same as false. If your conditional statement evaluates myCount > 0, then this might be worthwhile to have. Moreover, if you're running calculations based on the value here, 0 could be useful. If you're trying to test for null however, this is actually not going to work at all.
JSON4 {"myString": ""}
In this case, you're getting an empty string. Again, as with JSON2, it's defined, but it's empty. You could test for if (obj.myString == "") but you could not test for null or undefined.
JSON5 {"myString": "null"}
This is probably going to get you in trouble, because you're setting the string value to null; in this case, obj.myString == "null" however it is not == null.
JSON6 {"myArray": []}
This will tell you that your array myArray exists, but it's empty. This is useful if you're trying to perform a count or evaluation on myArray. For instance, say you wanted to evaluate the number of photos a user posted - you could do myArray.length and it would return 0: defined, but no photos posted.
null is not zero. It is not a value, per se: it is a value outside the domain of the variable indicating missing or unknown data.
There is only one way to represent null in JSON. Per the specs (RFC 4627 and json.org):
2.1. Values
A JSON value MUST be an object, array, number, or string, or one of
the following three literal names:
false null true
There is only one way to represent null; that is with null.
console.log(null === null); // true
console.log(null === true); // false
console.log(null === false); // false
console.log(null === 'null'); // false
console.log(null === "null"); // false
console.log(null === ""); // false
console.log(null === []); // false
console.log(null === 0); // false
That is to say; if any of the clients that consume your JSON representation use the === operator; it could be a problem for them.
no value
If you want to convey that you have an object whose attribute myCount has no value:
{ "myCount": null }
no attribute / missing attribute
What if you to convey that you have an object with no attributes:
{}
Client code will try to access myCount and get undefined; it's not there.
empty collection
What if you to convey that you have an object with an attribute myCount that is an empty list:
{ "myCount": [] }
I would use null to show that there is no value for that particular key. For example, use null to represent that "number of devices in your household connects to internet" is unknown.
On the other hand, use {} if that particular key is not applicable. For example, you should not show a count, even if null, to the question "number of cars that has active internet connection" is asked to someone who does not own any cars.
I would avoid defaulting any value unless that default makes sense. While you may decide to use null to represent no value, certainly never use "null" to do so.
I would pick "default" for data type of variable (null for strings/objects, 0 for numbers), but indeed check what code that will consume the object expects. Don't forget there there is sometimes distinction between null/default vs. "not present".
Check out null object pattern - sometimes it is better to pass some special object instead of null (i.e. [] array instead of null for arrays or "" for strings).
According to the JSON spec, the outermost container does not have to be a dictionary (or 'object') as implied in most of the comments above. It can also be a list or a bare value (i.e. string, number, boolean or null). If you want to represent a null value in JSON, the entire JSON string (excluding the quotes containing the JSON string) is simply null. No braces, no brackets, no quotes. You could specify a dictionary containing a key with a null value ({"key1":null}), or a list with a null value ([null]), but these are not null values themselves - they are proper dictionaries and lists. Similarly, an empty dictionary ({}) or an empty list ([]) are perfectly fine, but aren't null either.
In Python:
>>> print json.loads('{"key1":null}')
{u'key1': None}
>>> print json.loads('[null]')
[None]
>>> print json.loads('[]')
[]
>>> print json.loads('{}')
{}
>>> print json.loads('null')
None
This is a personal and situational choice. The important thing to remember is that the empty string and the number zero are conceptually distinct from null.
In the case of a count you probably always want some valid number (unless the count is unknown or undefined), but in the case of strings, who knows? The empty string could mean something in your application. Or maybe it doesn't. That's up to you to decide.
'null' is best for practical use
FWIW, using PHP as an example, PHP interprets empty sets as entries made by PHP...
// This loop will iterate one item with the value 'the car'
$empty_json = '["the car"]';
$some_json_array = json_decode($empty_json);
foreach ($some_json_array as $i) {
echo "PHP sees one item";
}
output: PHP sees the car
// This loop will iterate one item, but with no values
$empty_json = '[""]';
$some_json_array = json_decode($empty_json);
foreach ($some_json_array as $i) {
echo "PHP sees: $i";
}
output: PHP sees
// This loop will iterate nothing because PHP's `json_decode()` function knew it was `null`
$empty_json = 'null';
$some_json_array = json_decode($empty_json);
foreach ($some_json_array as $i) {
echo "PHP sees one item";
}
output: (nothing, foreach will not loop)

How can my MVC controller produce JSON in the following format?

I'm trying to integrate jQuery validation engine with my MVC project to perform inline validation. I have a field inside a jQuery form which is calling to an MVC controller and expects a JSON response. According this article written by the plugin's author...
Now this will send the field in ajax to the defined url, and wait for
the response, the response need to be an array encoded in json
following this syntax: ["id1", boolean status].
So in php you would do this: echo json_encode($arrayToJs);
How to achieve this in ASP.NET MVC4?
My current controller looks like this.
public JsonResult FunctionName(string fieldValue)
{
return Json((new { foo = "bar", baz = "Blech" }), JsonRequestBehavior.AllowGet);
}
The response body shows that it returns key value pairs that look like this
{"foo":"bar","baz":"Blech"}
How can I return JSON in the expected format?
The square brackets indicate an array within a JSON object.
See this article: http://www.w3schools.com/json/json_syntax.asp
This test code:
return Json(new object[] { "id1", false }, JsonRequestBehavior.AllowGet);
should return:
["id1",false]
If you want to return an array within the json, which i think you do. Then you can return a Dictionary. Your not seeing an array in the json output now because of the anonymous type you are passing in is two key values.
public JsonResult MyMethodName(string name)
{
IDictionary<string, bool> myDict = LoadDictionaryFromSomewhere();
return Json(myDict, JsonRequestBehaviour.AllowGet);
}

NancyFX: How do I deserialize dynamic types via BrowserResponse.Body.DeserializeJson (unit tests)

I have the following NancyFX unit test. I use the Shouldly assertion library to give the set of extensions methods that start .Should---
[Fact]
public void Assessment__Should_return_assessment_state_for_specified_user()
{
const AssessmentState assessmentState = AssessmentState.Passed;
var user = Fake.Mentor();
using (var db = Fake.Db())
{
db.Save(user);
Fake.Assessment(user.Id, db, assessmentState);
db.ClearStaleIndexes();
}
var response = Fake.Browser(user.UserName, user.Password)
.Get("/assessment/state/" + user.Id, with => with.HttpRequest());
//var result = (dynamic)body.DeserializeJson<ExpandoObject>();
var result = (dynamic) JsonConvert.DeserializeObject<ExpandoObject>(response.Body.AsString());
result.ShouldNotBe(null);
((AssessmentState) result.State).ShouldBe(assessmentState);
}
This test calls a AssessmentService uri defined as /assessment/state/" + user.Id which returns a simple JSON object definition that has a single property State of type (enum) AssessmentState, either Passed, Failed or NotStarted.
Here is the service handler so you can see there are no tricks.
Get["/assessment/state/{userid}"] = parameters =>
{
var assessment = AssessmentService.GetByUserId(Db, (string)parameters.userid);
return assessment == null ? HttpStatusCode.NotFound : Response.AsJson(new
{
assessment.State
});
};
And here is an example the JSON this service call returns:
{"State":1}
Everything works fine until I try to Deserialize the JSON returned by the fake Nancy browser. First I tried to use the built in method provided by Nancy's BrowserResponse.Body object:
var result = (dynamic)response.Body.DeserializeJson<ExpandoObject>();
This deserializes to an empty object. Which is no good. However, if we use the Newtonsoft equivalent then everything is fine (almost).
var result = (dynamic) JsonConvert.DeserializeObject<ExpandoObject>(response.Body.AsString());
The JSON deserialization now works and so the following Shouldly assertion passes with flying colours:
((AssessmentState) result.State).ShouldBe(assessmentState);
However, for reasons that I suspect have to do with anonymous types, the following line fails at run-time (it compiles fine).
result.ShouldNotBe(null);
That is quite a lot of information. Let me distil it down to two questions:
Why does Nancy's built in JSON deserializer not work given that the Newtonsoft version does?
How do I work with the dynamic types generated by the JSON de-serialisation so that the Shouldly extension methods do not cause a run-time exception?
Thanks
I can't answer the first question, but WRT Shouldly and dynamic types, Shouldly's ShouldNotBe method is an extension method on object. The DLR doesn't allow you to call extension methods on objects typed as dynamic (hence the runtime binder exception you're seeing)
I'd suggest that if you want to call ShouldNotBe(null) on result, you'd have to cast it to an object first (ie: ((object)result).ShouldNotBe(null))
-x