Representando null em JSON

423

Qual é o método preferido para retornar valores nulos em JSON? Existe uma preferência diferente para primitivas?

Por exemplo, se meu objeto no servidor tiver um número inteiro chamado "myCount" sem valor, o JSON mais correto para esse valor seria:

{}

ou

{
    "myCount": null
}

ou

{
    "myCount": 0
}

Mesma pergunta para Strings - se eu tiver uma string nula "myString" no servidor, é o melhor JSON:

{}

ou

{
    "myString": null
}

ou

{
    "myString": ""
}

ou (senhor me ajude)

{
    "myString": "null"
}

Gosto da convenção de coleções ser representada no JSON como uma coleção vazia http://jtechies.blogspot.nl/2012/07/item-43-return-empty-arrays-or.html

Uma matriz vazia seria representada:

{
    "myArray": []
}

Resumo do EDIT

O argumento de 'preferência pessoal' parece realista, mas míope, como comunidade, estaremos consumindo um número cada vez maior de serviços / fontes diferentes. As convenções para a estrutura JSON ajudariam a normalizar o consumo e a reutilização desses serviços. Quanto ao estabelecimento de um padrão, eu sugeriria a adoção da maioria das convenções de Jackson com algumas exceções:

  • Os objetos são preferíveis aos primitivos.
  • Coleções vazias são preferidas a nulas.
  • Objetos sem valor são representados como nulos.
  • As primitivas retornam seu valor.

Se você estiver retornando um objeto JSON com valores principalmente nulos, poderá ter um candidato para refatorar em vários serviços.

{

    "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

}

O JSON acima foi gerado a partir da seguinte classe 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()));
    }
}

Dependência do Maven:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.3.0</version>
</dependency>
pherris
fonte
5
Não existe o melhor caminho. Escolha o que é mais fácil de consumir para o cliente em seu caso de uso concreto. No espírito de retornar coleções vazias em vez de null, considere se o seu cliente é melhor com a string vazia ou null- uma string contendo a palavra "null" é indistinguível de um valor válido, não faça isso.
Philipp Reichart
3
0 ou uma sequência vazia pode muito bem ter um significado diferente de nulo, que pode ter um significado diferente do atributo que não existe. Se você deseja representar nulo, use nulo. É o mais explícito.
John Sheehan
No Objective-C, há uma NSNullclasse definida que possui uma instância singleton. Uma referência a essa instância é equivalente a JSON null. Eu acho que outro idioma poderia fazer a mesma coisa. Obviamente, seria necessário verificar a classe do objeto recebido antes de converter para a classe presumida - ter "reconhecimento nulo", por assim dizer.
Hot Licks
2
Observe que ter uma lista "nula" também não é uma prática recomendada em Java: se a lista estiver vazia, inicialize-a em uma lista vazia. Se for necessário permanecer vazio (por exemplo, porque será substituído por atacado por uma nova lista em vez de modificado para adicionar valores), inicialize- o na lista vazia (por exemplo Collections.emptyList()). Fazer isso evita erros de referência nulos que, caso contrário, podem ser uma dor.
Periata Breatta
@ HotLicks - isso só é possível porque o Objective-C é digitado dinamicamente. Em Java, por exemplo, você não poderia ter uma Nullclasse (útil) porque só seria capaz de atribuir seus valores a objetos de seu próprio tipo ou tipo Object.
Periata Breatta

Respostas:

379

Vamos avaliar a análise de cada um:

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

O tl; dr aqui:

O fragmento na variável json2 é a maneira que a especificação JSON indica que nulldeve ser representada. Mas, como sempre, isso depende do que você está fazendo - às vezes a maneira "certa" de fazer isso nem sempre funciona para a sua situação. Use seu julgamento e tome uma decisão informada.


JSON1 {}

Isso retorna um objeto vazio. Não há dados lá, e isso só lhe dirá que qualquer chave que você esteja procurando (seja ela myCountou outra coisa) é do tipo undefined.


JSON2 {"myCount": null}

Nesse caso, myCounté realmente definido, embora seu valor seja null. Isso não é o mesmo que "não undefinede não null" e, se você estivesse testando uma condição ou outra, isso poderia ser bem-sucedido, enquanto o JSON1 falharia.

Essa é a maneira definitiva de representar de nullacordo com a especificação JSON .


JSON3 {"myCount": 0}

Nesse caso, myCount é 0. Isso não é o mesmo que nulle não é o mesmo que false. Se sua declaração condicional for avaliada myCount > 0, isso pode valer a pena. Além disso, se você estiver executando cálculos com base no valor aqui, 0 pode ser útil. Se você estiver tentando testar, no nullentanto, isso realmente não vai funcionar.


JSON4 {"myString": ""}

Nesse caso, você está recebendo uma string vazia. Novamente, como no JSON2, ele está definido, mas está vazio. Você pode testar, if (obj.myString == "")mas não pode testar nullou undefined.


JSON5 {"myString": "null"}

Isso provavelmente vai causar problemas, porque você está definindo o valor da string como nulo; neste caso, obj.myString == "null"no entanto, é não == null .


JSON6 {"myArray": []}

Isso informará que sua matriz myArrayexiste, mas está vazia. Isso é útil se você estiver tentando realizar uma contagem ou avaliação myArray. Por exemplo, digamos que você queira avaliar o número de fotos que um usuário postou - você poderia fazer myArray.lengthe ele retornaria 0: definido, mas sem fotos postadas.

brandonscript
fonte
1
Muito obrigado, muito útil. Apenas um pequeno nó lateral; quando o Play Json (scala) serializa a opção [String] = Nenhum resultado é JSON1ie{}
Neil
207

nullnão é zero. Não é um valor em si : é um valor fora do domínio da variável que indica dados ausentes ou desconhecidos.

Existe apenas uma maneira de representar nullno JSON. De acordo com as especificações ( RFC 4627 e json.org ):

2.1 Valores

Um valor JSON DEVE ser um objeto, matriz, número ou string ou um dos
os três nomes literais a seguir:

  falso nulo verdadeiro

insira a descrição da imagem aqui

Nicholas Carey
fonte
8
É uma pena que nulo tenha que estar presente. 4 caracteres para nada. Seria bom simplesmente excluir completamente o valor. json = '{"myValue":}';
Richard A quadling
119
@ Richard A Quadling - Eu sou um seguidor dos "Programas de Hal Abelson", para que as pessoas leiam, e apenas acidentalmente para as máquinas executarem ". Prefiro a palavra 'null', confirmando a intenção do programador, e não apenas uma questão de omissão acidental.
Scott Smith
13
@Dave May: "Os valores JSON não são programas" - Meu ponto é sobre sinalizar a intenção de maneira inequívoca. Sim, custa quatro caracteres extras e, para alguns aplicativos, a diferença pode ser significativa. Em muitos casos, porém, os benefícios de cometer erros parecem muito superiores aos benefícios de pequenas otimizações.
Scott Smith
11
@Dave Além disso, de acordo com json.org, JSON "é fácil para os humanos lerem e escreverem".
Sophivorus 06/07/19
14
Observe também que se você tiver problemas com 4 caracteres ASCII, o JSON não é a melhor abordagem, observe o JSON binário ou melhor para um formato binário puro.
PhoneixS
26

Existe apenas uma maneira de representar null; isso é com 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

Isso é para dizer; se algum dos clientes que consome sua representação JSON usar o ===operador; poderia ser um problema para eles.

sem valor

Se você deseja transmitir que possui um objeto cujo atributo myCountnão tem valor:

{ "myCount": null }

nenhum atributo / atributo ausente

E se você transmitir que possui um objeto sem atributos:

{}

O código do cliente tentará acessar myCounte obter undefined; não está lá.

coleção vazia

E se você transmitir que possui um objeto com um atributo myCountque é uma lista vazia:

{ "myCount": [] }
dnozay
fonte
Marque +1 bons exemplos com comparações, mas seria útil distinguir entre javascript e json, ou seja, a representação de null em javascript não precisa corresponder à do json (embora isso ocorra).
Mladen B.
15

Eu usaria nullpara mostrar que não há valor para essa chave específica. Por exemplo, use nullpara representar que "o número de dispositivos em sua casa se conecta à Internet" é desconhecido.

Por outro lado, use {}se essa chave específica não for aplicável. Por exemplo, você não deve mostrar uma contagem, mesmo que nulla pergunta "número de carros com conexão ativa à Internet" seja solicitada a alguém que não possui carros.

Eu evitaria padronizar qualquer valor, a menos que esse padrão faça sentido. Embora você decida usar nullpara não representar nenhum valor, certamente nunca o "null"fará.

marcoseu
fonte
7

Eu escolheria "default" para o tipo de dados da variável ( nullpara strings / objetos, 0para números), mas, de fato, verificaria qual código que consumirá o objeto espera. Não se esqueça, às vezes há uma distinção entre null/ default vs. "not present".

Confira o padrão de objetos nulos - às vezes é melhor passar algum objeto especial em vez de null(ou seja, []matriz em vez de nullmatrizes ou ""seqüências de caracteres).

Alexei Levenkov
fonte
2

Esta é uma escolha pessoal e situacional. O importante é lembrar que a sequência vazia e o número zero são conceitualmente distintos null.

No caso de um, countvocê provavelmente sempre quer um número válido (a menos que countseja desconhecido ou indefinido), mas no caso de strings, quem sabe? A cadeia vazia pode significar algo no seu aplicativo. Ou talvez não. Cabe a você decidir.

Wayne
fonte
1

De acordo com a especificação JSON , o contêiner mais externo não precisa ser um dicionário (ou 'objeto'), como está implícito na maioria dos comentários acima. Também pode ser uma lista ou um valor simples (ou seja, string, número, booleano ou nulo). Se você deseja representar um valor nulo em JSON, a cadeia JSON inteira (excluindo as aspas que contêm a cadeia JSON) é simples null. Sem chaves, sem colchetes, sem aspas. Você pode especificar um dicionário que contenha uma chave com valor nulo ( {"key1":null}) ou uma lista com valor nulo ( [null]), mas esses valores não são nulos - eles são dicionários e listas adequados. Da mesma forma, um dicionário vazio ( {}) ou uma lista vazia ( []) são perfeitamente adequados, mas também não são nulos.

Em 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
fonte
Observe que é a gramática do McKeeman Form, na barra lateral direita da página de especificações JSON vinculada, que valida a asserção de que ele nullé um JSON válido. O texto e as ilustrações do corpo principal são ambíguos e, se algo parecer sugerir, apenas objetos e matrizes são válidos na raiz.
yoyoyoyosef