web-dev-qa-db-fra.com

Comment analyser un flux d'entrée JSON

J'utilise Java pour appeler une URL qui renvoie un objet JSON:

url = new URL("my URl");
urlInputStream = url.openConnection().getInputStream();

Comment puis-je convertir la réponse en chaîne et l'analyser? 

50

Je suggère que vous deviez utiliser un lecteur pour convertir votre InputStream en. 

BufferedReader streamReader = new BufferedReader(new InputStreamReader(in, "UTF-8")); 
StringBuilder responseStrBuilder = new StringBuilder();

String inputStr;
while ((inputStr = streamReader.readLine()) != null)
    responseStrBuilder.append(inputStr);
new JSONObject(responseStrBuilder.toString());

J'ai essayé in.toString () mais il retourne: 

getClass().getName() + '@' + Integer.toHexString(hashCode())

(comme la documentation dit qu'il dérive de toString from Object)

77

Toutes les réponses actuelles partent du principe qu'il est correct d'extraire le code JSON entier en mémoire, ce qui présente l'avantage d'un InputStream: vous pouvez lire l'entrée au fur et à mesure. Si vous souhaitez éviter de lire l'intégralité du fichier Json en une seule fois, nous vous conseillons d'utiliser la bibliothèque Jackson (qui est ma préférée, mais je suis sûr que d'autres, comme Gson, ont des fonctions similaires).

Avec Jackson, vous pouvez utiliser un JsonParser pour lire une section à la fois. Vous trouverez ci-dessous un exemple de code écrit qui encapsule la lecture d’un tableau de JsonObjects dans un Iterator. Si vous voulez juste voir un exemple de Jackson, regardez les méthodes initJsonParser, initFirstElement et initNextObject.

public class JsonObjectIterator implements Iterator<Map<String, Object>>, Closeable {
    private static final Logger LOG = LoggerFactory.getLogger(JsonObjectIterator.class);

    private final InputStream inputStream;
    private JsonParser jsonParser;
    private boolean isInitialized;

    private Map<String, Object> nextObject;

    public JsonObjectIterator(final InputStream inputStream) {
        this.inputStream = inputStream;
        this.isInitialized = false;
        this.nextObject = null;
    }

    private void init() {
        this.initJsonParser();
        this.initFirstElement();
        this.isInitialized = true;
    }

    private void initJsonParser() {
        final ObjectMapper objectMapper = new ObjectMapper();
        final JsonFactory jsonFactory = objectMapper.getFactory();

        try {
            this.jsonParser = jsonFactory.createParser(inputStream);
        } catch (final IOException e) {
            LOG.error("There was a problem setting up the JsonParser: " + e.getMessage(), e);
            throw new RuntimeException("There was a problem setting up the JsonParser: " + e.getMessage(), e);
        }
    }

    private void initFirstElement() {
        try {
            // Check that the first element is the start of an array
            final JsonToken arrayStartToken = this.jsonParser.nextToken();
            if (arrayStartToken != JsonToken.START_ARRAY) {
                throw new IllegalStateException("The first element of the Json structure was expected to be a start array token, but it was: " + arrayStartToken);
            }

            // Initialize the first object
            this.initNextObject();
        } catch (final Exception e) {
            LOG.error("There was a problem initializing the first element of the Json Structure: " + e.getMessage(), e);
            throw new RuntimeException("There was a problem initializing the first element of the Json Structure: " + e.getMessage(), e);
        }

    }

    private void initNextObject() {
        try {
            final JsonToken nextToken = this.jsonParser.nextToken();

            // Check for the end of the array which will mean we're done
            if (nextToken == JsonToken.END_ARRAY) {
                this.nextObject = null;
                return;
            }

            // Make sure the next token is the start of an object
            if (nextToken != JsonToken.START_OBJECT) {
                throw new IllegalStateException("The next token of Json structure was expected to be a start object token, but it was: " + nextToken);
            }

            // Get the next product and make sure it's not null
            this.nextObject = this.jsonParser.readValueAs(new TypeReference<Map<String, Object>>() { });
            if (this.nextObject == null) {
                throw new IllegalStateException("The next parsed object of the Json structure was null");
            }
        } catch (final Exception e) {
            LOG.error("There was a problem initializing the next Object: " + e.getMessage(), e);
            throw new RuntimeException("There was a problem initializing the next Object: " + e.getMessage(), e);
        }
    }

    @Override
    public boolean hasNext() {
        if (!this.isInitialized) {
            this.init();
        }

        return this.nextObject != null;
    }

    @Override
    public Map<String, Object> next() {
        // This method will return the current object and initialize the next object so hasNext will always have knowledge of the current state

        // Makes sure we're initialized first
        if (!this.isInitialized) {
            this.init();
        }

        // Store the current next object for return
        final Map<String, Object> currentNextObject = this.nextObject;

        // Initialize the next object
        this.initNextObject();

        return currentNextObject;
    }

    @Override
    public void close() throws IOException {
        IOUtils.closeQuietly(this.jsonParser);
        IOUtils.closeQuietly(this.inputStream);
    }

}

Si vous ne vous souciez pas de l'utilisation de la mémoire, il serait certainement plus facile de lire le fichier en entier et de l'analyser comme un gros Json, comme mentionné dans d'autres réponses.

24
BoostHungry

Pour ceux qui ont souligné le fait que vous ne pouvez pas utiliser la méthode toString de InputStream comme ceci, voir https://stackoverflow.com/a/5445161/1304830 :

Ma réponse correcte serait alors:

import org.json.JSONObject;

public static String convertStreamToString(Java.io.InputStream is) {
    Java.util.Scanner s = new Java.util.Scanner(is).useDelimiter("\\A");
    return s.hasNext() ? s.next() : "";
}

...

JSONObject json = new JSONObject(convertStreamToString(url.openStream());
6
Fr4nz

utilisez jackson pour convertir le flux d'entrée json en carte ou en objet http://jackson.codehaus.org/

il y a aussi quelques autres bibliothèques utiles pour json, vous pouvez google: json java

6
Penkov Vladimir

Utilisez une bibliothèque.

  • GSON
  • Jackson
  • ou l'une des nombreuses autres bibliothèques JSON disponibles.
4
Dunes

Si vous aimez utiliser Jackson Databind (que Spring utilise par défaut pour sa HttpMessageConverters), vous pouvez utiliser l'API ObjectMapper.readTree (InputStream) . Par exemple,

ObjectMapper mapper = new ObjectMapper();
JsonNode json = mapper.readTree(myInputStream);
3
Somu

si vous avez un fichier JSON, vous pouvez le définir sur le dossier assets, puis appelez-le en utilisant ce code

InputStream in = mResources.getAssets().open("fragrances.json"); 
// where mResources object from Resources class
0
Sayed Saeed