il modo più semplice per leggere json da un URL in Java


246

Questo potrebbe essere una domanda stupida, ma qual è il modo più semplice per leggere e analizzare JSON da URL in Java ?

In Groovy, si tratta di poche righe di codice. Gli esempi di Java che trovo sono ridicolmente lunghi (e hanno un enorme blocco di gestione delle eccezioni).

Tutto quello che voglio fare è leggere il contenuto di questo link .


9
La gestione delle eccezioni è necessaria poiché java ti obbliga a gestire le eccezioni dichiarate. Cosa c'è di sbagliato nella gestione delle eccezioni?
Falmarri,

3
bene, il "java force you" è il problema più grande
Jonatan Cloutier il

9
Se java non ti costringesse a gestire le eccezioni, pensi che i programmi funzionerebbero e funzionerebbero bene? E se mi fosse stato chiesto di inserire la mia età in un programma e avessi dato snarfleblagger come input? Java dovrebbe consentire l'esecuzione del programma senza problemi? Se non si desidera gestire le eccezioni, dichiararle come lanciate dai metodi in cui possono verificarsi e guardare il proprio programma fallire quando qualcosa non va perfettamente.
Richard Barker,

2
Non è una domanda stupida. Soprattutto proveniente da PHP dove puoi farlo json_decode(file_get_contents($url));ed essere fatto!
dtbarne,

Risposte:


195

Usando l'artefatto di Maven org.json:jsonho ottenuto il seguente codice, che penso sia piuttosto breve. Non il più corto possibile, ma comunque utilizzabile.

package so4308554;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.nio.charset.Charset;

import org.json.JSONException;
import org.json.JSONObject;

public class JsonReader {

  private static String readAll(Reader rd) throws IOException {
    StringBuilder sb = new StringBuilder();
    int cp;
    while ((cp = rd.read()) != -1) {
      sb.append((char) cp);
    }
    return sb.toString();
  }

  public static JSONObject readJsonFromUrl(String url) throws IOException, JSONException {
    InputStream is = new URL(url).openStream();
    try {
      BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
      String jsonText = readAll(rd);
      JSONObject json = new JSONObject(jsonText);
      return json;
    } finally {
      is.close();
    }
  }

  public static void main(String[] args) throws IOException, JSONException {
    JSONObject json = readJsonFromUrl("https://graph.facebook.com/19292868552");
    System.out.println(json.toString());
    System.out.println(json.get("id"));
  }
}

3
invece di leggere carattere per carattere puoi usare readLine () su BufferedReader. Ciò ridurrà il numero di iterazioni di while loop.
kdabir,

7
Per che cosa? La readLinefunzione eseguirà quindi il ciclo e devo concatenare le righe anziché i caratteri, il che è più costoso. Ciò non manterrebbe il codice breve come lo è ora. Inoltre, nella notazione JSON non esiste il concetto di "linee", quindi perché dovrei leggerle come tali?
Roland Illig

4
Considera il IOUtils.toString(InputStream)metodo di Apache commons-io . Ciò dovrebbe farti risparmiare alcune linee e responsabilità.
Mark Tielemans,

3
Perché visualizzo questo errore "Il costruttore JSONObject (String) non è definito" nella riga di JSONObject json = new JSONObject (jsonText); nel metodo "readJsonFromUrl" ..? @RolandIllig
Karthick pop il

2
Con GSON, Jackson, Boon, Genson e altri, avete solo bisogno di alimentare la fonte: o solo URL, o al massimo InputStream. Mentre il codice sopra può essere abbreviato per l' org.jsonuso, assicurati di verificare altre librerie disponibili - non è necessario scrivere più di 1-3 righe di codice per questa attività.
StaxMan

68

Ecco un paio di versioni alternative con Jackson (dal momento che ci sono più di un modo in cui potresti volere dati come):

  ObjectMapper mapper = new ObjectMapper(); // just need one
  // Got a Java class that data maps to nicely? If so:
  FacebookGraph graph = mapper.readValue(url, FaceBookGraph.class);
  // Or: if no class (and don't need one), just map to Map.class:
  Map<String,Object> map = mapper.readValue(url, Map.class);

E in particolare il solito caso (IMO) in cui si desidera gestire oggetti Java, è possibile creare una riga:

FacebookGraph graph = new ObjectMapper().readValue(url, FaceBookGraph.class);

Anche altre librerie come Gson supportano metodi a una riga; perché molti esempi mostrano sezioni molto più lunghe è strano. E ancora peggio è che molti esempi usano una libreria org.json obsoleta; potrebbe essere stata la prima cosa in giro, ma ci sono una mezza dozzina di alternative migliori, quindi ci sono pochissime ragioni per usarlo.


Che cos'è l'URL qui? È una stringa o un oggetto URL o byte []?
Dinesh

1
Stavo pensando di java.net.URLma o si lavora, così come un sacco di altre fonti ( File, InputStream, Reader, String).
StaxMan

4
Esso dovrebbe essere java.net.URL nell'esempio di cui sopra, altrimenti si cercherà di analizzare stringa 'http: // ....' come JSON, che produrrà un errore
zbstof

@Zotov Sì. Il passaggio Stringrichiederebbe che i contenuti siano JSON e non la codifica testuale di URI / URL da utilizzare.
StaxMan

2
Token non riconosciuto 'https': era in attesa ('vero', 'falso' o 'null')
Damir Olejar

60

Il modo più semplice: usa gson, la libreria goto json di google. https://code.google.com/p/google-gson/

Ecco un esempio Sto andando a questo sito Web geolocalizzazione gratuito e analizzando il json e mostrando il mio codice postale. (basta mettere questa roba in un metodo principale per provarlo)

    String sURL = "http://freegeoip.net/json/"; //just a string

    // Connect to the URL using java's native library
    URL url = new URL(sURL);
    URLConnection request = url.openConnection();
    request.connect();

    // Convert to a JSON object to print data
    JsonParser jp = new JsonParser(); //from gson
    JsonElement root = jp.parse(new InputStreamReader((InputStream) request.getContent())); //Convert the input stream to a json element
    JsonObject rootobj = root.getAsJsonObject(); //May be an array, may be an object. 
    String zipcode = rootobj.get("zip_code").getAsString(); //just grab the zipcode

1
Perché visualizzo l'errore "NetworkOnMainThreadException"? Devo utilizzare un AsyncTask o esiste un altro modo? In questo esempio hai ricevuto anche questo errore?
Benetz,

rootobj.get("zip_code").getAsString();
Errore di battitura

Come importare jsonParser? Ricevo sempre l'errore: "Errore: (69, 9) errore: impossibile trovare la classe di simboli JsonParser"
MAESTRO_DE

1
Aggiungi la dipendenza maven <dipendenza> <gruppoId> com.google.code.gson </groupId> <artifactId> gson </artifactId> <versione> 2.8.0 </version> </dipendenza> per inserire JsonParse nel tuo pom file.
sashikanta,

può essere semplificato e gestito in modo tipico con Gson come: MyResponseObject response = new GsonBuilder (). create (). fromJson (new InputStreamReader ((InputStream) request.getContent ()), MyResponseObject.class);
Gregor,

42

Se non ti dispiace usare un paio di librerie, puoi farlo in una sola riga.

Include le librerie IOUtils e json.org di Apache Commons .

JSONObject json = new JSONObject(IOUtils.toString(new URL("https://graph.facebook.com/me"), Charset.forName("UTF-8")));

Hai qualche idea sul perché l'aggiunta della dipendenza alla pendenza impedirebbe l'installazione di questa app sul mio Google Pixel XL?
andrdoiddev,

@andrdoiddev - Dovresti porlo come domanda separata. È più generale per lo sviluppo di Apache Commons, Gradle e Android.
ezwrighter il

1
Questo è piuttosto vecchio ora, ma è ancora una buona soluzione, quindi nel caso in cui @andrdoiddev o chiunque altro abbia ancora bisogno delle dipendenze Gradle, questi sono quelli che sto usando: gruppo di compilazione: 'org.json', nome: 'json ', versione:' 20180813 'gruppo di compilazione:' commons-io ', nome:' commons-io ', versione:' 2.6 '
r02

Supponiamo che tu stia eseguendo più richieste, salvando le risposte json su un JSONArray e quindi scrivendo JSONArray su un file utilizzando FileWriter, quindi questa libreria NON ESCLUDE le doppie virgolette. Questo rende il file facilmente analizzabile su JSONArray.
Gh0sT

6

Usa HttpClient per afferrare il contenuto dell'URL. E quindi utilizzare la libreria da json.org per analizzare JSON. Ho usato queste due librerie su molti progetti e sono state robuste e semplici da usare.

Oltre a ciò, puoi provare a utilizzare una libreria java API di Facebook. Non ho alcuna esperienza in questo settore, ma c'è una domanda sullo overflow dello stack relativa all'uso di un'API di Facebook in Java . Potresti voler guardare RestFB come una buona scelta per una libreria da usare.


5

Ho fatto il parser json nel modo più semplice, eccolo qui

package com.inzane.shoapp.activity;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

public class JSONParser {

static InputStream is = null;
static JSONObject jObj = null;
static String json = "";

// constructor
public JSONParser() {

}

public JSONObject getJSONFromUrl(String url) {

    // Making HTTP request
    try {
        // defaultHttpClient
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);

        HttpResponse httpResponse = httpClient.execute(httpPost);
        HttpEntity httpEntity = httpResponse.getEntity();
        is = httpEntity.getContent();

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    try {
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                is, "iso-8859-1"), 8);
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
            sb.append(line + "\n");
            System.out.println(line);
        }
        is.close();
        json = sb.toString();

    } catch (Exception e) {
        Log.e("Buffer Error", "Error converting result " + e.toString());
    }

    // try parse the string to a JSON object
    try {
        jObj = new JSONObject(json);
    } catch (JSONException e) {
        Log.e("JSON Parser", "Error parsing data " + e.toString());
        System.out.println("error on parse data in jsonparser.java");
    }

    // return JSON String
    return jObj;

}
}

questa classe restituisce l'oggetto json dall'URL

e quando vuoi l'oggetto json devi semplicemente chiamare questa classe e il metodo nella tua classe Activity

il mio codice è qui

String url = "your url";
JSONParser jsonParser = new JSONParser();
JSONObject object = jsonParser.getJSONFromUrl(url);
String content=object.getString("json key");

qui la "chiave json" indica la chiave nel tuo file json

questo è un semplice esempio di file json

{
    "json":"hi"
}

Qui "json" è la chiave e "ciao" è valore

Questo porterà il tuo valore json a stringare il contenuto.


1
Penso che non sia il "modo più semplice"
stand alone

3

È molto facile, usando jersey-client, basta includere questa dipendenza maven:

<dependency>
  <groupId>org.glassfish.jersey.core</groupId>
  <artifactId>jersey-client</artifactId>
  <version>2.25.1</version>
</dependency>

Quindi invocalo usando questo esempio:

String json = ClientBuilder.newClient().target("http://api.coindesk.com/v1/bpi/currentprice.json").request().accept(MediaType.APPLICATION_JSON).get(String.class);

Quindi utilizzare Google Gson per analizzare JSON:

Gson gson = new Gson();
Type gm = new TypeToken<CoinDeskMessage>() {}.getType();
CoinDeskMessage cdm = gson.fromJson(json, gm);

Niente contro la risposta, ma tanti problemi con il pacchetto jersey-client ... è un casino di errori.
Johnny Bigoode,

non ho riscontrato alcun problema. puoi indicare alcune specifiche e / o alternative?
user3892260

I problemi che ho riscontrato erano correlati all'errore classnotfound, non erano esattamente sicuri della causa, perché non sono riuscito a risolverlo.
Johnny Bigoode,

3

Ho trovato questo di gran lunga il modo più semplice.

Usa questo metodo:

public static String getJSON(String url) {
        HttpsURLConnection con = null;
        try {
            URL u = new URL(url);
            con = (HttpsURLConnection) u.openConnection();

            con.connect();


            BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line + "\n");
            }
            br.close();
            return sb.toString();


        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            if (con != null) {
                try {
                    con.disconnect();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        return null;
    }

E usalo in questo modo:

String json = getJSON(url);
JSONObject obj;
   try {
         obj = new JSONObject(json);
         JSONArray results_arr = obj.getJSONArray("results");
         final int n = results_arr.length();
            for (int i = 0; i < n; ++i) {
                // get the place id of each object in JSON (Google Search API)
                String place_id = results_arr.getJSONObject(i).getString("place_id");
            }


   }

È presente un'eccezione ClassCastException. Modifica l'URL della linea u = nuovo URL (url); a questo URL u = nuovo URL (null, url, new sun.net.www.protocol.https.Handler ()); per far funzionare questo codice
sunny arya

2

Non sono sicuro che sia efficace, ma questo è uno dei modi possibili:

Leggi json dall'uso dell'URL url.openStream()e leggi il contenuto in una stringa.

costruire un oggetto JSON con questa stringa (altro su json.org )

JSONObject(java.lang.String source)
      Construct a JSONObject from a source JSON text string.

0

Volevo aggiungere una risposta aggiornata qui poiché (in qualche modo) recenti aggiornamenti a JDK hanno reso un po 'più semplice la lettura del contenuto di un URL HTTP. Come altri hanno già detto, sarà comunque necessario utilizzare una libreria JSON per eseguire l'analisi, poiché JDK non ne contiene attualmente una. Ecco alcune delle librerie JSON più comunemente usate per Java:

Per recuperare JSON da un URL, questo sembra essere il modo più semplice usando rigorosamente le classi JDK (ma probabilmente non qualcosa che vorresti fare per grandi payload), Java 9 ha introdotto: https://docs.oracle.com/en/ java / JavaSE / 11 / docs / api / java.base / java / io / InputStream.html # readAllBytes ()

try(java.io.InputStream is = new java.net.URL("https://graph.facebook.com/me").openStream()) {
    String contents = new String(is.readAllBytes());
}

Per analizzare JSON usando la libreria GSON, per esempio

com.google.gson.JsonElement element = com.google.gson.JsonParser.parseString(contents); //from 'com.google.code.gson:gson:2.8.6'

0

Ecco un esempio completo di come analizzare il contenuto di Json. L'esempio prende le statistiche delle versioni di Android (trovate nel codice sorgente di Android Studio qui , che si collega a qui ).

Copia il file "distributions.json" che ottieni da lì in res / raw, come fallback.

build.gradle

    implementation 'com.google.code.gson:gson:2.8.6'

manifesto

  <uses-permission android:name="android.permission.INTERNET" />

MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        if (savedInstanceState != null)
            return
        thread {
            // https://cs.android.com/android/platform/superproject/+/studio-master-dev:tools/adt/idea/android/src/com/android/tools/idea/stats/DistributionService.java
            var root: JsonArray
            Log.d("AppLog", "loading...")
            try {
                HttpURLConnection.setFollowRedirects(true)
                val statsUrl = "https://dl.google.com/android/studio/metadata/distributions.json" //just a string
                val url = URL(statsUrl)
                val request: HttpURLConnection = url.openConnection() as HttpURLConnection
                request.connectTimeout = 3000
                request.connect()
                InputStreamReader(request.content as InputStream).use {
                    root = JsonParser.parseReader(it).asJsonArray
                }
            } catch (e: Exception) {
                Log.d("AppLog", "error while loading from Internet, so using fallback")
                e.printStackTrace()
                InputStreamReader(resources.openRawResource(R.raw.distributions)).use {
                    root = JsonParser.parseReader(it).asJsonArray
                }
            }
            val decimalFormat = DecimalFormat("0.00")
            Log.d("AppLog", "result:")

            root.forEach {
                val androidVersionInfo = it.asJsonObject
                val versionNickName = androidVersionInfo.get("name").asString
                val versionName = androidVersionInfo.get("version").asString
                val versionApiLevel = androidVersionInfo.get("apiLevel").asInt
                val marketSharePercentage = androidVersionInfo.get("distributionPercentage").asFloat * 100f
                Log.d("AppLog", "\"$versionNickName\" - $versionName - API$versionApiLevel - ${decimalFormat.format(marketSharePercentage)}%")
            }
        }
    }
}

In alternativa alla dipendenza, puoi anche usare questo invece:

InputStreamReader(request.content as InputStream).use {
    val jsonArray = JSONArray(it.readText())
}

e il fallback:

InputStreamReader(resources.openRawResource(R.raw.distributions)).use {
    val jsonArray = JSONArray(it.readText())
}

Il risultato dell'esecuzione di questo:

loading...
result:
"Ice Cream Sandwich" - 4.0 - API15 - 0.20%
"Jelly Bean" - 4.1 - API16 - 0.60%
"Jelly Bean" - 4.2 - API17 - 0.80%
"Jelly Bean" - 4.3 - API18 - 0.30%
"KitKat" - 4.4 - API19 - 4.00%
"Lollipop" - 5.0 - API21 - 1.80%
"Lollipop" - 5.1 - API22 - 7.40%
"Marshmallow" - 6.0 - API23 - 11.20%
"Nougat" - 7.0 - API24 - 7.50%
"Nougat" - 7.1 - API25 - 5.40%
"Oreo" - 8.0 - API26 - 7.30%
"Oreo" - 8.1 - API27 - 14.00%
"Pie" - 9.0 - API28 - 31.30%
"Android 10" - 10.0 - API29 - 8.20%
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.