einfachste Möglichkeit, json von einer URL in Java zu lesen

245

Dies mag eine dumme Frage sein, aber was ist der einfachste Weg, JSON von einer URL in Java zu lesen und zu analysieren ?

In Groovy geht es nur um wenige Codezeilen. Java-Beispiele, die ich finde, sind lächerlich lang (und haben einen riesigen Block für die Ausnahmebehandlung).

Ich möchte nur den Inhalt dieses Links lesen .

Pomponius
quelle
9
Die Ausnahmebehandlung ist erforderlich, da Java Sie zwingt, alle deklarierten Ausnahmen zu behandeln. Was ist falsch an der Ausnahmebehandlung?
Falmarri
3
Nun, die "Java Force You" ist das größte Problem
Jonatan Cloutier
9
Wenn Java Sie nicht gezwungen hätte, Ausnahmen zu behandeln, würden Programme Ihrer Meinung nach immer noch gut laufen? Was wäre, wenn ich gebeten würde, mein Alter in ein Programm einzugeben, und ich Snarfleblagger als Eingabe gebe? Sollte Java zulassen, dass das Programm ohne Probleme ausgeführt wird? Wenn Sie Ausnahmen nicht behandeln möchten, deklarieren Sie sie als von den Methoden ausgelöst, in denen sie auftreten können, und beobachten Sie, wie Ihr Programm fehlschlägt, wenn etwas nicht stimmt.
Richard Barker
2
Überhaupt keine blöde Frage. Besonders wenn man von PHP kommt, wo man das machen kann json_decode(file_get_contents($url));und fertig ist!
dtbarne

Antworten:

193

Mit dem Maven-Artefakt habe org.json:jsonich den folgenden Code erhalten, der meiner Meinung nach ziemlich kurz ist. Nicht so kurz wie möglich, aber immer noch verwendbar.

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"));
  }
}
Roland Illig
quelle
3
Anstatt zeichenweise zu lesen, können Sie readLine () für BufferedReader verwenden. Dies reduziert die Anzahl der Iterationen der while-Schleife.
Kdabir
6
Wozu? Die readLineFunktion führt dann die Schleife durch, und ich muss die Zeilen anstelle der Zeichen verketten, was teurer ist. Das würde den Code nicht so kurz halten wie jetzt. Darüber hinaus gibt es in der JSON-Notation kein Konzept für "Linien". Warum sollte ich sie also als solche lesen?
Roland Illig
4
Betrachten Sie die IOUtils.toString(InputStream)Methode von Apache Commons-Io . Das sollte Ihnen einige Zeilen und Verantwortung ersparen.
Mark Tielemans
3
Warum ich diesen Fehler erhalte "Der Konstruktor JSONObject (String) ist undefiniert" in der Zeile von JSONObject json = new JSONObject (jsonText); in der Methode "readJsonFromUrl" ..? @ RolandIllig
Karthick Pop
2
Bei GSON, Jackson, Boon, Genson und anderen müssen Sie nur die Quelle eingeben: entweder nur die URL oder höchstens InputStream. Während der obige Code für die org.jsonVerwendung kurz sein kann, stellen Sie sicher, dass Sie andere verfügbare Bibliotheken überprüfen. Für diese Aufgabe müssen nicht mehr als 1-3 Codezeilen geschrieben werden.
StaxMan
68

Hier sind einige alternative Versionen mit Jackson (da es mehrere Möglichkeiten gibt, Daten zu erhalten):

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

Und speziell der übliche Fall (IMO), in dem Sie sich mit Java-Objekten befassen möchten, kann zu einem einzigen Liner gemacht werden:

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

Andere Bibliotheken wie Gson unterstützen ebenfalls einzeilige Methoden. Warum viele Beispiele viel längere Abschnitte zeigen, ist seltsam. Und noch schlimmer ist, dass viele Beispiele die veraltete Bibliothek org.json verwenden. Es war vielleicht das erste, was es gab, aber es gibt ein halbes Dutzend bessere Alternativen, so dass es kaum einen Grund gibt, es zu verwenden.

StaxMan
quelle
Was ist URL hier? Ist es eine Zeichenfolge oder ein URL-Objekt oder ein Byte []?
Dinesh
1
Ich dachte an , java.net.URLaber irgendein man arbeitet, sowie viele andere Quellen ( File, InputStream, Reader, String).
StaxMan
4
Im obigen Beispiel sollte es java.net.URL sein, andernfalls wird versucht, die Zeichenfolge 'http: // ....' als json zu analysieren, was zu einem Fehler führt
zbstof
@ Zotov Ja. Für Stringdie Übergabe muss der Inhalt JSON sein und nicht die Textcodierung der zu verwendenden URI / URL.
StaxMan
2
Nicht erkanntes Token 'https': erwartete ('wahr', 'falsch' oder 'null')
Damir Olejar
60

Der einfachste Weg: Verwenden Sie gson, Googles eigene goto json-Bibliothek. https://code.google.com/p/google-gson/

Hier ist ein Beispiel. Ich gehe auf diese kostenlose Geolocator-Website und analysiere den JSON und zeige meine Postleitzahl an. (Setzen Sie dieses Zeug einfach in eine Hauptmethode, um es zu testen)

    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
user2654569
quelle
1
Warum erhalte ich den Fehler 'NetworkOnMainThreadException'? Ich muss eine AsyncTask verwenden oder gibt es einen anderen Weg? Haben Sie in diesem Beispiel auch diesen Fehler erhalten?
Benetz
Tippfehler, sollte sein:rootobj.get("zip_code").getAsString();
Loopasam
Wie importiere ich den jsonParser? Ich erhalte immer die Fehlermeldung: 'Fehler: (69, 9) Fehler: Symbolklasse JsonParser kann nicht gefunden werden'
MAESTRO_DE
1
Bitte fügen Sie die Maven-Abhängigkeit <Abhängigkeit> <Gruppen-ID> com.google.code.gson </ Gruppen-ID> <ArtefaktId> gson </ Artefakt-ID> <Version> 2.8.0 </ Version> </ Abhängigkeit> hinzu, um JsonParse in Ihren POM zu bekommen Datei.
Sashikanta
kann mit Gson vereinfacht und typsicher behandelt werden wie: MyResponseObject response = new GsonBuilder (). create (). fromJson (neuer InputStreamReader ((InputStream) request.getContent ()), MyResponseObject.class);
Gregor
42

Wenn es Ihnen nichts ausmacht, ein paar Bibliotheken zu verwenden, können Sie dies in einer einzigen Zeile tun.

Schließen Sie Apache Commons IOUtils & json.org- Bibliotheken ein.

JSONObject json = new JSONObject(IOUtils.toString(new URL("https://graph.facebook.com/me"), Charset.forName("UTF-8")));
ezwrighter
quelle
Haben Sie eine Vermutung, warum das Hinzufügen der Abhängigkeit zum Gradle die Installation dieser App auf meinem Google Pixel XL verhindern würde?
andrdoiddev
@andrdoiddev - Sie sollten dies als separate Frage stellen. Es ist allgemeiner für Apache Commons, Gradle und Android Development.
Ezwrighter
1
Dies ist jetzt ziemlich alt, aber immer noch eine gute Lösung. Für den Fall, dass @andrdoiddev oder jemand anderes noch die Gradle-Abhängigkeiten benötigt, verwende ich diese: compile group: 'org.json', name: 'json ', Version:' 20180813 'Kompilierungsgruppe:' commons-io ', Name:' commons-io ', Version:' 2.6 '
r02
Angenommen, Sie lösen mehrere Anforderungen aus, speichern die JSON-Antworten in einem JSONArray und schreiben das JSONArray dann mit FileWriter in eine Datei. Dann entgeht diese Bibliothek keinen doppelten Anführungszeichen. Dadurch kann die Datei problemlos zurück in JSONArray analysiert werden.
Gh0sT
6

Verwenden Sie HttpClient , um den Inhalt der URL abzurufen. Verwenden Sie dann die Bibliothek von json.org , um den JSON zu analysieren. Ich habe diese beiden Bibliotheken in vielen Projekten verwendet und sie waren robust und einfach zu bedienen.

Ansonsten können Sie versuchen, eine Facebook-API-Java-Bibliothek zu verwenden. Ich habe keine Erfahrung in diesem Bereich, aber es gibt eine Frage zum Stapelüberlauf im Zusammenhang mit der Verwendung einer Facebook-API in Java . Möglicherweise möchten Sie RestFB als eine gute Wahl für eine Bibliothek betrachten.

Jon Snyder
quelle
5

Ich habe den JSON-Parser auf einfachste Weise erstellt, hier ist er

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;

}
}

Diese Klasse gibt das JSON-Objekt von der URL zurück

und wenn Sie das json-Objekt möchten, rufen Sie einfach diese Klasse und die Methode in Ihrer Activity-Klasse auf

Mein Code ist hier

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

Hier wird der "JSON-Schlüssel" als der Schlüssel in Ihrer JSON-Datei bezeichnet

Dies ist ein einfaches Beispiel für eine JSON-Datei

{
    "json":"hi"
}

Hier ist "json" der Schlüssel und "hi" der Wert

Dadurch wird Ihr JSON-Wert zum String-Inhalt.

Ribin Das
quelle
1
Ich denke, es ist nicht der "einfachste Weg"
allein
3

Mit Jersey-Client ist es sehr einfach, nur diese Maven-Abhängigkeit einzuschließen:

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

Rufen Sie es dann anhand dieses Beispiels auf:

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

Verwenden Sie dann Gson von Google, um den JSON zu analysieren:

Gson gson = new Gson();
Type gm = new TypeToken<CoinDeskMessage>() {}.getType();
CoinDeskMessage cdm = gson.fromJson(json, gm);
user3892260
quelle
Nichts gegen die Antwort, aber so viele Probleme mit dem Trikot-Client-Paket ... es ist ein Durcheinander von Fehlern.
Johnny Bigoode
Ich habe keine Probleme damit festgestellt. Können Sie einige Besonderheiten und / oder Alternativen aufzeigen?
user3892260
Die Probleme, die ich fand, bezogen sich auf einen nicht gefundenen Fehler. Ich war mir über die Ursache nicht ganz sicher, da ich es nicht geschafft habe, ihn zu beheben.
Johnny Bigoode
3

Ich habe festgestellt, dass dies bei weitem der einfachste Weg ist.

Verwenden Sie diese Methode:

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

Und benutze es so:

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


   }
Mastercool
quelle
Sie haben dort eine ClassCastException-Ausnahme. Ändern Sie die Zeilen-URL u = neue URL (URL); zu dieser URL u = neue URL (null, url, new sun.net.www.protocol.https.Handler ()); damit dieser Code funktioniert
sonnige Arya
2

Ich bin nicht sicher, ob dies effizient ist, aber dies ist einer der möglichen Wege:

Lesen Sie json aus der URL-Verwendung url.openStream()und lesen Sie den Inhalt in eine Zeichenfolge.

Erstellen Sie ein JSON-Objekt mit dieser Zeichenfolge (mehr unter json.org ).

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

Ich wollte hier eine aktualisierte Antwort hinzufügen, da (etwas) die jüngsten Aktualisierungen des JDK das Lesen des Inhalts einer HTTP-URL etwas erleichtert haben. Wie bereits erwähnt, müssen Sie für die Analyse weiterhin eine JSON-Bibliothek verwenden, da das JDK derzeit keine enthält. Hier sind einige der am häufigsten verwendeten JSON-Bibliotheken für Java:

Um JSON von einer URL abzurufen, scheint dies der einfachste Weg zu sein, ausschließlich JDK-Klassen zu verwenden (aber wahrscheinlich nicht etwas, das Sie für große Nutzdaten tun möchten). Java 9 führte Folgendes ein: 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());
}

Zum Beispiel zum Parsen des JSON mithilfe der GSON-Bibliothek

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

Hier finden Sie eine vollständige Auswahl zum Parsen von Json-Inhalten. In diesem Beispiel wird die Statistik der Android-Versionen verwendet ( hier im Quellcode von Android Studio zu finden , der hier verlinkt ist ).

Kopieren Sie die Datei "Distributions.json", die Sie von dort erhalten, als Fallback in res / raw.

build.gradle

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

Manifest

  <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)}%")
            }
        }
    }
}

Alternativ zur Abhängigkeit können Sie stattdessen auch Folgendes verwenden:

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

und der Fallback:

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

Das Ergebnis dieser Ausführung:

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%
Android-Entwickler
quelle