Conversión de datos JSON a objeto Java

262

Quiero poder acceder a las propiedades desde una cadena JSON dentro de mi método de acción Java. La cadena está disponible simplemente diciendo myJsonString = object.getJson(). A continuación se muestra un ejemplo del aspecto que puede tener la cadena:

{
    'title': 'ComputingandInformationsystems',
    'id': 1,
    'children': 'true',
    'groups': [{
        'title': 'LeveloneCIS',
        'id': 2,
        'children': 'true',
        'groups': [{
            'title': 'IntroToComputingandInternet',
            'id': 3,
            'children': 'false',
            'groups': []
        }]
    }]
}

En esta cadena, cada objeto JSON contiene una matriz de otros objetos JSON. La intención es extraer una lista de ID donde cualquier objeto dado que posee una propiedad de grupo que contiene otros objetos JSON. Miré el Gson de Google como un posible complemento JSON. ¿Alguien puede ofrecer alguna forma de orientación sobre cómo puedo generar Java a partir de esta cadena JSON?

Faiyet
fuente

Respuestas:

329

Miré el Gson de Google como un posible complemento JSON. ¿Alguien puede ofrecer alguna forma de orientación sobre cómo puedo generar Java a partir de esta cadena JSON?

Google Gson admite genéricos y beans anidados. El []en JSON representa una matriz y debe correlacionarse con una colección de Java como Listo simplemente una matriz de Java simple. El {}en JSON representa un objeto y debe mapearse a una Mapclase Java o solo a alguna clase JavaBean.

Tiene un objeto JSON con varias propiedades cuya groupspropiedad representa una matriz de objetos anidados del mismo tipo. Esto se puede analizar con Gson de la siguiente manera:

package com.stackoverflow.q1688099;

import java.util.List;
import com.google.gson.Gson;

public class Test {

    public static void main(String... args) throws Exception {
        String json = 
            "{"
                + "'title': 'Computing and Information systems',"
                + "'id' : 1,"
                + "'children' : 'true',"
                + "'groups' : [{"
                    + "'title' : 'Level one CIS',"
                    + "'id' : 2,"
                    + "'children' : 'true',"
                    + "'groups' : [{"
                        + "'title' : 'Intro To Computing and Internet',"
                        + "'id' : 3,"
                        + "'children': 'false',"
                        + "'groups':[]"
                    + "}]" 
                + "}]"
            + "}";

        // Now do the magic.
        Data data = new Gson().fromJson(json, Data.class);

        // Show it.
        System.out.println(data);
    }

}

class Data {
    private String title;
    private Long id;
    private Boolean children;
    private List<Data> groups;

    public String getTitle() { return title; }
    public Long getId() { return id; }
    public Boolean getChildren() { return children; }
    public List<Data> getGroups() { return groups; }

    public void setTitle(String title) { this.title = title; }
    public void setId(Long id) { this.id = id; }
    public void setChildren(Boolean children) { this.children = children; }
    public void setGroups(List<Data> groups) { this.groups = groups; }
    
    public String toString() {
        return String.format("title:%s,id:%d,children:%s,groups:%s", title, id, children, groups);
    }
}

Bastante simple, ¿no es así? Solo tenga un JavaBean adecuado y llame Gson#fromJson().

Ver también:

BalusC
fuente
44
Performant? ¿Realmente lo has medido? Si bien GSON tiene un conjunto de características razonable, pensé que el rendimiento era una especie de punto débil (según [ cowtowncoder.com/blog/archives/2009/09/entry_326.html] ) Como por ejemplo: pensé que GSON realmente no necesitaba setters, y se basó en los campos. Entonces el código podría simplificarse ligeramente.
StaxMan el
3
Lo uso en una aplicación de Android. No es la solución más rápida posible, pero es lo suficientemente simple de programar para justificar la falta de rendimiento para el usuario hasta ahora. Quizás en una versión posterior de la aplicación se elimine para una solución más rápida.
Janusz
1
Velocidad de Wrt, si es lo suficientemente rápido, es lo suficientemente rápido. Acabo de comentar sobre la referencia al buen rendimiento esperado. En cuanto al conjunto de características, Jackson maneja los mismos anidamientos, capas y genéricos, por lo que no es de allí de donde proviene la diferencia de velocidad. Tener getters y setters no afecta el rendimiento de ninguna manera medible (para los paquetes que conozco), por lo que definitivamente puede tenerlos allí.
StaxMan
97
+1 para el "paquete com.stackoverflow.q1688099;". Por alguna razón me hizo reír.
GargantuChet
1
public String toString () {return new Gson (). toJson (this); // Use esto en lugar de escribir cada variable}
Prakash
45

Bewaaaaare de Gson! Es muy bueno, muy grande, pero el segundo desea hacer otra cosa que simples objetos nada, que fácilmente podría necesitar para empezar a construir sus propios serializadores (que no es que dura).

Además, si tiene una matriz de Objetos y deserializa algo de json en esa matriz de Objetos, ¡los tipos verdaderos están PERDIDOS! ¡Los objetos completos ni siquiera se copiarán! Use XStream .. Que, si usa el jsondriver y establece la configuración adecuada, codificará los tipos feos en el json real, para que no pierda nada. Un pequeño precio a pagar (feo json) por la verdadera serialización.

Tenga en cuenta que Jackson soluciona estos problemas y es más rápido que GSON.

Jor
fuente
2
He escrito un tenedor de Gson que soluciona estos problemas (y evita todas las anotaciones de Jackson): github.com/winterstein/flexi-gson
Daniel Winterstein
26

Curiosamente, el único procesador JSON decente mencionado hasta ahora ha sido GSON.

Aquí hay más buenas opciones:

  • Jackson ( Github ): potente enlace de datos (JSON a / desde POJOs), transmisión (ultrarrápida), modelo de árbol (conveniente para acceso sin tipo)
  • Flex-JSON : serialización altamente configurable

EDITAR (agosto / 2013):

Uno más a considerar:

  • Genson : funcionalidad similar a Jackson, cuyo objetivo es ser más fácil de configurar por el desarrollador
StaxMan
fuente
15

O con Jackson:

String json = "...
ObjectMapper m = new ObjectMapper();
Set<Product> products = m.readValue(json, new TypeReference<Set<Product>>() {});
Gene De Lisa
fuente
Esto dará error, no se puede deserializar la instancia de java.util.HashSet fuera del token
START_OBJECT
7

Si, por cualquier cambio, se encuentra en una aplicación que ya utiliza http://restfb.com/ , puede hacer lo siguiente:

import com.restfb.json.JsonObject;

...

JsonObject json = new JsonObject(jsonString);
json.get("title");

etc.

cherouvim
fuente
su solución es más corta y más comprensible, ¿por qué solo recibe 3 votos a favor? ¿Hay algo mal?
Jeff
4

Código java fácil y funcional para convertir JSONObjectaJava Object

Employee.java

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Generated;

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@Generated("org.jsonschema2pojo")
@JsonPropertyOrder({
"id",
"firstName",
"lastName"
})
public class Employee {

@JsonProperty("id")
private Integer id;
@JsonProperty("firstName")
private String firstName;
@JsonProperty("lastName")
private String lastName;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

/**
*
* @return
* The id
*/
@JsonProperty("id")
public Integer getId() {
return id;
}

/**
*
* @param id
* The id
*/
@JsonProperty("id")
public void setId(Integer id) {
this.id = id;
}

/**
*
* @return
* The firstName
*/
@JsonProperty("firstName")
public String getFirstName() {
return firstName;
}

/**
*
* @param firstName
* The firstName
*/
@JsonProperty("firstName")
public void setFirstName(String firstName) {
this.firstName = firstName;
}

/**
*
* @return
* The lastName
*/
@JsonProperty("lastName")
public String getLastName() {
return lastName;
}

/**
*
* @param lastName
* The lastName
*/
@JsonProperty("lastName")
public void setLastName(String lastName) {
this.lastName = lastName;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}

LoadFromJSON.java

import org.codehaus.jettison.json.JSONObject;

import com.fasterxml.jackson.databind.ObjectMapper;

public class LoadFromJSON {

    public static void main(String args[]) throws Exception {
        JSONObject json = new JSONObject();
        json.put("id", 2);
        json.put("firstName", "hello");
        json.put("lastName", "world");

        byte[] jsonData = json.toString().getBytes();

        ObjectMapper mapper = new ObjectMapper();
        Employee employee = mapper.readValue(jsonData, Employee.class);

        System.out.print(employee.getLastName());

    }
}
Rahul Raina
fuente
¿Cómo acceder a estas propiedades json en JSP?
Zoran777
Si no quieres usarlo en la página JSP, el código sigue siendo el mismo. La clase Employee.java será la misma que es. Pero el Código escrito en LoadFromJSON.java se copiará en la página jsp con la importación adecuada de cada clase. Descanse no hay cambio en absoluto.
Rahul Raina
4
HashMap keyArrayList = new HashMap();
Iterator itr = yourJson.keys();
while (itr.hasNext())
{
    String key = (String) itr.next();
    keyArrayList.put(key, yourJson.get(key).toString());
}
CALOR
fuente
3

Si utiliza algún tipo de mapas especiales con claves o valores también de mapas especiales, verá que no está contemplado por la implementación de google.

Juanma
fuente
2

¿Qué hay de malo con las cosas estándar?

JSONObject jsonObject = new JSONObject(someJsonString);
JSONArray jsonArray = jsonObject.getJSONArray("someJsonArray");
String value = jsonArray.optJSONObject(i).getString("someJsonValue");
Kevin
fuente
es terriblemente lento: github.com/fabienrenaud/java-json-benchmark recientemente en el trabajo, dupliqué el rendimiento (uso de CPU reducido a la mitad, corte de latencia en alto) de nuestros servidores de productos al cambiar todas las llamadas de ser / deserialización org.json para usar jackson.
fabien
0

Prueba boon:

https://github.com/RichardHightower/boon

Es malvado rápido:

https://github.com/RichardHightower/json-parsers-benchmark

No confíes en mi palabra ... mira el punto de referencia de Gatling.

https://github.com/gatling/json-parsers-benchmark

(Hasta 4 veces en algunos casos, y fuera de los 100 de la prueba. También tiene un modo de superposición de índice que es aún más rápido. Es joven pero ya tiene algunos usuarios).

Puede analizar JSON a Maps y Lists más rápido que cualquier otra lib puede analizar a un JSON DOM y eso es sin el modo Index Overlay. Con el modo Boon Index Overlay, es aún más rápido.

También tiene un modo JSON lax muy rápido y un modo de analizador PLIST. :) (y tiene una memoria súper baja, directo desde el modo de bytes con codificación UTF-8 sobre la marcha).

También tiene el modo JSON más rápido para JavaBean también.

Es nuevo, pero si lo que estás buscando es velocidad y API simple, no creo que haya una API más rápida o más minimalista.

RickHigh
fuente
¿Puede proporcionar un enlace para obtener documentación actualizada de la última versión? A partir de hoy, encontré 0.4, pero no puedo encontrar fácilmente un enlace de documento coincidente o tutorial para esa versión. Gracias
Bizmarck
Aquí hay un tutorial github.com/RichardHightower/boon/wiki/Boon-JSON-in-five-minutes Boon está en el repositorio público de Maven. Está en 0.27 más o menos.
RickHigh
richardhightower.github.io/site/releases tiene 0.4, así que pensé que era lo último. He estado revisando a Boon para un proyecto en el trabajo, ¿tiene una anotación equivalente a @JsonIgnore de Jackson?
Bizmarck
boon está en el extremo inferior del rendimiento de ser / deserialización: github.com/fabienrenaud/java-json-benchmark Elija jackson o dsljson para el rendimiento. @RickHigh: No pude abrir un problema en su github, estoy más que dispuesto a mejorar mi punto de referencia o corregir su interpretación si hay algo mal / que me perdí.
fabien
0

Dependiendo del formato JSON de entrada (cadena / archivo), cree un jSONString. El objeto de clase de mensaje de muestra correspondiente a JSON se puede obtener de la siguiente manera:

Mensaje msgFromJSON = new ObjectMapper (). ReadValue (jSONString, Message.class);

Shailendra Singh
fuente
0

La forma más fácil es que puede utilizar este método de conversión de valores suaves, que es un método personalizado en el que puede convertir jsonData en su clase Dto específica.

Dto response = softConvertValue(jsonData, Dto.class);


public static <T> T softConvertValue(Object fromValue, Class<T> toValueType) 
{
    ObjectMapper objMapper = new ObjectMapper();
    return objMapper
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
        .convertValue(fromValue, toValueType);
}
Dipen Chawla
fuente