Representando nulo en JSON

423

¿Cuál es el método preferido para devolver valores nulos en JSON? ¿Hay una preferencia diferente por las primitivas?

Por ejemplo, si mi objeto en el servidor tiene un número entero llamado "myCount" sin valor, el JSON más correcto para ese valor sería:

{}

o

{
    "myCount": null
}

o

{
    "myCount": 0
}

La misma pregunta para Strings: si tengo una cadena nula "myString" en el servidor, es el mejor JSON:

{}

o

{
    "myString": null
}

o

{
    "myString": ""
}

o (señor, ayúdame)

{
    "myString": "null"
}

Me gusta la convención para que las colecciones se representen en el JSON como una colección vacía http://jtechies.blogspot.nl/2012/07/item-43-return-empty-arrays-or.html

Una matriz vacía estaría representada:

{
    "myArray": []
}

EDITAR resumen

El argumento de 'preferencia personal' parece realista, pero miope en eso, como comunidad consumiremos un número cada vez mayor de servicios / fuentes dispares. Las convenciones para la estructura JSON ayudarían a normalizar el consumo y la reutilización de dichos servicios. En cuanto a establecer un estándar, sugeriría adoptar la mayoría de las convenciones de Jackson con algunas excepciones:

  • Se prefieren los objetos sobre los primitivos.
  • Se prefieren las colecciones vacías a las nulas.
  • Los objetos sin valor se representan como nulos.
  • Las primitivas devuelven su valor.

Si está devolviendo un objeto JSON con valores mayormente nulos, puede tener un candidato para refactorizar en múltiples servicios.

{

    "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

}

El JSON anterior se generó a partir de la siguiente clase Java.

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()));
    }
}

Dependencia de Maven:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.3.0</version>
</dependency>
pherris
fuente
55
No hay mejor manera. Elija lo que es más fácil de consumir para el cliente en su caso de uso concreto. En el espíritu de devolver colecciones vacías en lugar de nullconsiderar si su cliente es mejor con la cadena vacía o si nulluna cadena que contiene la palabra "nulo" no se puede distinguir de un valor válido, no lo haga.
Philipp Reichart
3
0 o una cadena vacía bien podría tener un significado diferente de nulo, lo que podría tener un significado diferente del atributo no existente. Si desea representar nulo, use nulo. Es lo más explícito.
John Sheehan
En Objective-C hay una NSNullclase definida que tiene una instancia singleton. Una referencia a esa instancia es equivalente a la de JSON null. Supongo que otro idioma podría hacer lo mismo. Por supuesto, uno tendría que verificar la clase del objeto recibido antes de lanzar a la clase presunta, por lo tanto, tenga "nulo conocimiento".
Hot Licks
2
Tenga en cuenta que tener una lista "nula" tampoco es la mejor práctica en Java: si se espera que la lista esté vacía, inicialícela en una lista vacía. Si es necesario que permanezca vacío (por ejemplo, porque se reemplazará al por mayor por una nueva lista en lugar de modificarse para agregar valores), inicialícelo en la lista vacía (es decir Collections.emptyList()). Al hacerlo, se evitan errores de referencia nulos que, de lo contrario, pueden ser un dolor.
Periata Breatta
@HotLicks: eso solo es posible porque Objective-C se escribe dinámicamente. En Java, por ejemplo, no podría tener una Nullclase (útil) porque solo podría asignar sus valores a objetos de su propio tipo o de tipo Object.
Periata Breatta

Respuestas:

379

Vamos a evaluar el análisis de cada uno:

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: []}

El tl; dr aquí:

El fragmento en la variable json2 es la forma en que la especificación JSON indica nullque se debe representar. Pero, como siempre, depende de lo que esté haciendo, a veces la forma "correcta" de hacerlo no siempre funciona para su situación. Use su criterio y tome una decisión informada.


JSON1 {}

Esto devuelve un objeto vacío. No hay datos allí, y solo le dirá que cualquier clave que esté buscando (ya sea myCountu otra cosa) es de tipo undefined.


JSON2 {"myCount": null}

En este caso, myCountse define realmente, aunque su valor es null. Esto no es lo mismo que "no undefinedy no null", y si estuviera probando una condición u otra, esto podría tener éxito mientras que JSON1 fallaría.

Esta es la forma definitiva de representar nullsegún la especificación JSON .


JSON3 {"myCount": 0}

En este caso, myCount es 0. Eso no es lo mismo que null, y no es lo mismo que false. Si su declaración condicional se evalúa myCount > 0, entonces podría valer la pena tenerla. Además, si está ejecutando cálculos basados ​​en el valor aquí, 0 podría ser útil. nullSin embargo, si está tratando de realizar una prueba , esto en realidad no va a funcionar en absoluto.


JSON4 {"myString": ""}

En este caso, obtienes una cadena vacía. De nuevo, como con JSON2, está definido, pero está vacío. Podrías hacer una prueba if (obj.myString == "")pero no podrías hacer una prueba para nullo undefined.


JSON5 {"myString": "null"}

Esto probablemente lo meterá en problemas, porque está configurando el valor de la cadena en nulo; en este caso, obj.myString == "null"sin embargo, es no == null .


JSON6 {"myArray": []}

Esto le dirá que su matriz myArrayexiste, pero está vacía. Esto es útil si está intentando realizar un conteo o evaluación myArray. Por ejemplo, supongamos que desea evaluar la cantidad de fotos que publicó un usuario; podría hacerlo myArray.lengthy volvería 0: definido, pero no hay fotos publicadas.

Brandonscript
fuente
1
Muchas gracias, muy útil. Solo un pequeño nodo lateral; cuando Play Json (scala) serializa la Opción [String] = Ninguno de los resultados es, es JSON1decir{}
Neil
207

nullno es cero No es un valor, per se : es un valor fuera del dominio de la variable que indica datos faltantes o desconocidos.

Solo hay una forma de representar nullen JSON. Según las especificaciones ( RFC 4627 y json.org ):

2.1. Valores

Un valor JSON DEBE ser un objeto, matriz, número o cadena, o uno de
los siguientes tres nombres literales:

  falso nulo verdadero

ingrese la descripción de la imagen aquí

Nicholas Carey
fuente
8
Es una pena que nulo tenga que estar presente. 4 personajes para nada. Hubiera sido agradable simplemente excluir el valor por completo. json = '{"myValue":}';
Richard A Quadling
119
@Richard A Quadling: soy un seguidor de "Los programas de Hal Abelson deben escribirse para que la gente los lea y, de paso, para que las máquinas los ejecuten". Prefiero la palabra 'nulo', que confirma la intención del programador, y no solo una cuestión de omisión accidental.
Scott Smith
13
@Dave May: "Los valores JSON no son programas" - Mi punto es sobre señalar la intención de una manera inequívoca. Sí, cuesta cuatro caracteres adicionales, y para algunas aplicaciones la diferencia puede ser significativa. Sin embargo, en muchos casos, los beneficios de hacer que los errores se vean mal superan con creces los beneficios de las optimizaciones menores.
Scott Smith
11
@Dave Además, según json.org, JSON "es fácil de leer y escribir para los humanos".
Sophivorus
14
También tenga en cuenta que si tiene problemas con 4 caracteres ASCII, JSON no es el mejor enfoque, mire JSON binario o mejor a un formato binario puro.
PhoneixS
26

Solo hay una forma de representar null; eso es con 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

Es decir; si alguno de los clientes que consumen su representación JSON usa el ===operador; Podría ser un problema para ellos.

sin valor

Si desea transmitir que tiene un objeto cuyo atributo myCountno tiene valor:

{ "myCount": null }

sin atributo / atributo faltante

¿Qué pasaría si transmitiera que tiene un objeto sin atributos?

{}

El código del cliente intentará acceder myCounty obtener undefined; no está ahí.

colección vacía

¿Qué pasaría si transmitiera que tiene un objeto con un atributo myCountque es una lista vacía?

{ "myCount": [] }
dnozay
fuente
+1 buenos ejemplos con comparaciones, pero sería útil distinguir entre javascript y json, lo que significa que la representación de nulo en javascript no tenía que coincidir con la de json (aunque sí lo hace).
Mladen B.
15

Solía nullmostrar que no hay valor para esa clave en particular. Por ejemplo, use nullpara representar que "la cantidad de dispositivos en su hogar se conecta a internet" es desconocida.

Por otro lado, use {}si esa clave en particular no es aplicable. Por ejemplo, no debe mostrar un recuento, incluso si null, a la pregunta "número de automóviles que tienen conexión activa a Internet" se le hace a alguien que no posee ningún automóvil.

Evitaría el valor predeterminado a menos que ese valor predeterminado tenga sentido. Si bien puede decidir usarlo nullpara no representar ningún valor, ciertamente nunca "null"lo haga.

marcoseu
fuente
7

Elegiría "predeterminado" para el tipo de datos de la variable ( nullpara cadenas / objetos, 0para números), pero de hecho verificaría qué código que consumirá el objeto espera. No olvide que a veces hay una distinción entre null/ default vs. "no presente".

Verifique el patrón de objeto nulo : a veces es mejor pasar algún objeto especial en lugar de null(es decir, []matriz en lugar de nullpara matrices o ""cadenas).

Alexei Levenkov
fuente
2

Esta es una elección personal y situacional. Lo importante para recordar es que la cadena vacía y el número cero son conceptualmente distintos de null.

En el caso de un count, probablemente siempre desee un número válido (a menos que countsea ​​desconocido o indefinido), pero en el caso de las cadenas, ¿quién sabe? La cadena vacía podría significar algo en su aplicación. O tal vez no. Eso depende de ti decidir.

Wayne
fuente
1

Según la especificación JSON , el contenedor más externo no tiene que ser un diccionario (u 'objeto') como se implica en la mayoría de los comentarios anteriores. También puede ser una lista o un valor simple (es decir, cadena, número, booleano o nulo). Si desea representar un valor nulo en JSON, toda la cadena JSON (excluyendo las comillas que contienen la cadena JSON) es simplemente null. Sin llaves, sin corchetes, sin comillas. Puede especificar un diccionario que contenga una clave con un valor nulo ( {"key1":null}), o una lista con un valor nulo ( [null]), pero estos no son valores nulos en sí mismos, son diccionarios y listas adecuados. Del mismo modo, un diccionario vacío ( {}) o una lista vacía ( []) están perfectamente bien, pero tampoco son nulos.

En 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
iggie
fuente
Tenga en cuenta que es la gramática del formulario McKeeman en la barra lateral derecha de la página de especificaciones JSON vinculada lo que valida la afirmación de que desnudo nullconstituye un JSON válido. El texto del cuerpo principal y las ilustraciones allí son ambiguos y, si algo parece sugerir, solo los objetos y las matrices son válidos en la raíz.
yoyoyoyosef