cara paling mudah untuk membaca json dari URL di java

245

Ini mungkin pertanyaan bodoh, tetapi apa cara paling sederhana untuk membaca dan mem-parsing JSON dari URL di Jawa ?

Dalam Groovy, ini masalah beberapa baris kode. Contoh Java yang saya temukan sangat panjang (dan memiliki blok penanganan pengecualian yang sangat besar).

Yang ingin saya lakukan adalah membaca isi tautan ini .

Pomponius
sumber
9
Penanganan pengecualian diperlukan karena java memaksa Anda untuk menangani pengecualian yang dideklarasikan. Apa yang salah dengan penanganan pengecualian?
Falmarri
3
baik, "kekuatan java kamu" adalah masalah terbesar
Jonatan Cloutier
9
Jika java tidak memaksa Anda untuk menangani pengecualian, apakah menurut Anda program akan tetap berjalan dan berjalan dengan baik? Bagaimana jika saya diminta memasukkan usia saya ke dalam suatu program dan saya memberikan snarfleblagger sebagai masukan saya? Haruskah java mengizinkan program untuk mengeksekusi tanpa masalah? Jika Anda tidak ingin menangani pengecualian, maka nyatakan bahwa mereka dilemparkan oleh metode yang mungkin terjadi dan saksikan program Anda gagal ketika ada sesuatu yang tidak beres.
Richard Barker
2
Sama sekali bukan pertanyaan bodoh. Terutama datang dari PHP tempat Anda dapat melakukan ini json_decode(file_get_contents($url));dan selesai!
dtbarne

Jawaban:

193

Menggunakan artefak Maven org.json:jsonsaya mendapat kode berikut, yang menurut saya cukup singkat. Tidak sesingkat mungkin, tetapi masih bisa digunakan.

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
sumber
3
alih-alih membaca karakter demi karakter, Anda dapat menggunakan readLine () pada BufferedReader. Ini akan mengurangi jumlah iterasi loop sementara.
kdabir
6
Untuk apa? The readLinefungsi akan melakukan loop kemudian, dan saya harus menggabungkan garis-garis bukan karakter, yang lebih mahal. Itu tidak akan membuat kode sesingkat sekarang. Selanjutnya, dalam notasi JSON tidak ada konsep "garis", jadi mengapa saya harus membacanya seperti itu?
Roland Illig
4
Pertimbangkan IOUtils.toString(InputStream)metode Apache commons-io . Itu akan menyelamatkan Anda dari beberapa jalur dan tanggung jawab.
Mark Tielemans
3
Mengapa saya mendapatkan kesalahan ini "Konstruktor JSONObject (String) tidak terdefinisi" di baris JSONObject json = JSONObject baru (jsonText); dalam metode "readJsonFromUrl" ..? @RolandIllig
Karthick pop
2
Dengan GSON, Jackson, Boon, Genson, dan lainnya, Anda hanya perlu memberi makan sumber: baik URL saja, atau paling banyak InputStream. Meskipun kode di atas mungkin singkat untuk org.jsondigunakan, pastikan untuk memverifikasi lib lain yang tersedia - tidak perlu menulis lebih dari 1-3 baris kode untuk tugas ini.
StaxMan
68

Berikut adalah beberapa versi alternatif dengan Jackson (karena ada lebih dari satu cara Anda mungkin menginginkan data):

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

Dan khususnya kasus biasa (IMO) di mana Anda ingin berurusan dengan objek Java, dapat dibuat satu liner:

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

Lib lainnya seperti Gson juga mendukung metode satu baris; mengapa banyak contoh menunjukkan bagian yang jauh lebih lama aneh. Dan yang lebih buruk lagi adalah bahwa banyak contoh menggunakan pustaka org.json yang sudah usang; ini mungkin yang pertama, tetapi ada setengah lusin alternatif yang lebih baik sehingga sangat sedikit alasan untuk menggunakannya.

StaxMan
sumber
Apa url di sini? Apakah ini objek string atau URL atau byte []?
Dinesh
1
Saya berpikir untuk java.net.URLtapi salah satu karya, serta banyak sumber-sumber lain ( File, InputStream, Reader, String).
StaxMan
4
Ini harus menjadi java.net.URL dalam contoh di atas, jika tidak maka akan mencoba untuk tali parse 'http: // ....' sebagai json, yang akan menghasilkan kesalahan
zbstof
@Zotov Ya. Lewat Stringakan membutuhkan konten menjadi JSON, dan bukan pengkodean URI / URL yang harus digunakan.
StaxMan
2
Token yang tidak dikenal 'https': mengharapkan ('benar', 'salah' atau 'null')
Damir Olejar
60

Cara termudah: Gunakan gson, pustaka goto json milik google. https://code.google.com/p/google-gson/

Berikut ini contohnya. Saya akan mengunjungi situs web geolocator gratis ini dan mem-parsing json dan menampilkan kode pos saya. (cukup masukkan barang-barang ini di metode utama untuk mengujinya)

    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
pengguna2654569
sumber
1
Mengapa saya mendapatkan kesalahan 'NetworkOnMainThreadException'? Saya harus menggunakan AsyncTask atau ada cara lain? Dalam contoh ini apakah Anda mendapatkan kesalahan ini juga?
Benetz
Typo, seharusnya:rootobj.get("zip_code").getAsString();
loopasam
Bagaimana cara saya mengimpor jsonParser? Saya selalu mendapatkan kesalahan: 'Kesalahan: (69, 9) kesalahan: tidak dapat menemukan kelas simbol JsonParser'
MAESTRO_DE
1
Harap tambahkan maven dependency <dependency> <groupId> com.google.code.gson </groupId> <artifactId> gson </artifactId> <version> 2.8.0 </version> </dependency> untuk mendapatkan JsonParse di pom Anda mengajukan.
sashikanta
dapat disederhanakan dan ditangani dengan cara yang aman menggunakan Gson seperti: MyResponseObject response = new GsonBuilder (). create (). fromJson (InputStreamReader baru ((InputStream) request.getContent ()), MyResponseObject.class);
Gregor
42

Jika Anda tidak keberatan menggunakan beberapa pustaka, itu bisa dilakukan dalam satu baris.

Sertakan perpustakaan Apache Commons IOUtils & json.org .

JSONObject json = new JSONObject(IOUtils.toString(new URL("https://graph.facebook.com/me"), Charset.forName("UTF-8")));
ezwrighter
sumber
Apakah Anda memiliki dugaan mengapa menambahkan ketergantungan pada gradle akan mencegah aplikasi ini menginstal di Google Pixel XL saya?
andrdoiddev
@andrdoiddev - Anda harus menanyakannya sebagai pertanyaan terpisah. Ini lebih umum untuk Apache Commons, Gradle dan Pengembangan Android.
ezwrighter
1
Ini sudah cukup lama sekarang, tetapi masih merupakan solusi yang baik, jadi kalau-kalau @andrdoiddev atau orang lain masih membutuhkan dependensi Gradle, ini yang saya gunakan: kompilasi grup: 'org.json', nama: 'json ', versi:' 20180813 'kompilasi grup:' commons-io ', nama:' commons-io ', versi:' 2.6 '
r02
Katakanlah Anda memecat banyak permintaan, menyimpan respons json ke JSONArray dan kemudian menulis JSONArray ke file menggunakan FileWriter, maka perpustakaan ini TIDAK MELAKUKAN ESCAPE tanda kutip ganda. Ini membuat file mudah diurai kembali ke JSONArray.
Gh0sT
6

Gunakan HttpClient untuk mengambil konten URL. Dan kemudian gunakan perpustakaan dari json.org untuk mengurai JSON. Saya telah menggunakan dua perpustakaan ini di banyak proyek dan mereka kuat dan mudah digunakan.

Selain itu Anda dapat mencoba menggunakan perpustakaan java API Facebook. Saya tidak punya pengalaman di bidang ini, tetapi ada pertanyaan tentang stack overflow yang terkait dengan penggunaan Facebook API di java . Anda mungkin ingin melihat RestFB sebagai pilihan yang baik untuk digunakan oleh perpustakaan.

Jon Snyder
sumber
5

Saya telah melakukan parser json dengan cara paling sederhana, ini dia

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;

}
}

kelas ini mengembalikan objek json dari url

dan ketika Anda ingin objek json, Anda hanya memanggil kelas ini dan metode di kelas aktivitas Anda

kode saya ada di sini

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

di sini "kunci json" dilambangkan sebagai kunci dalam file json Anda

ini adalah contoh file json sederhana

{
    "json":"hi"
}

Di sini "json" adalah kunci dan "hai" adalah nilai

Ini akan mendapatkan nilai json Anda ke konten string.

Ribin Das
sumber
1
Saya pikir itu bukan "cara paling sederhana"
berdiri sendiri
3

Sangat mudah, menggunakan jersey-client, cukup masukkan dependensi pakar ini:

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

Kemudian panggil menggunakan contoh ini:

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

Kemudian gunakan Google Gson untuk mengurai JSON:

Gson gson = new Gson();
Type gm = new TypeToken<CoinDeskMessage>() {}.getType();
CoinDeskMessage cdm = gson.fromJson(json, gm);
pengguna3892260
sumber
Tidak ada yang menentang jawaban, tetapi begitu banyak masalah dengan paket jersey-client ... itu adalah kesalahan kesalahan.
Johnny Bigoode
saya belum pernah mengalami masalah dengannya. dapatkah Anda menunjukkan beberapa spesifik dan / atau alternatif?
user3892260
Masalah yang saya temukan terkait dengan kesalahan classnotfound, tidak yakin tentang penyebabnya, karena saya tidak berhasil memperbaikinya.
Johnny Bigoode
3

Saya telah menemukan ini sebagai cara termudah sejauh ini.

Gunakan metode ini:

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

Dan gunakan seperti ini:

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
sumber
Anda sudah mendapatkan pengecualian ClassCastException duduk di sana. Ubah URL baris u = URL baru (url); ke URL ini u = URL baru (null, url, new sun.net.www.protocol.https.Handler ()); agar kode ini berfungsi
sunny arya
2

Saya tidak yakin apakah ini efisien, tetapi ini adalah salah satu cara yang mungkin:

Baca json dari penggunaan url url.openStream()dan baca konten menjadi string.

buat objek JSON dengan string ini (selengkapnya di json.org )

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

Saya ingin menambahkan jawaban yang diperbarui di sini karena (agak) pembaruan terbaru untuk JDK telah membuatnya sedikit lebih mudah untuk membaca konten URL HTTP. Seperti yang dikatakan orang lain, Anda masih perlu menggunakan pustaka JSON untuk melakukan parsing, karena JDK saat ini tidak mengandung parsing. Berikut adalah beberapa pustaka JSON yang paling umum digunakan untuk Java:

Untuk mengambil JSON dari URL, ini tampaknya menjadi cara paling sederhana menggunakan kelas ketat JDK (tapi mungkin bukan sesuatu yang ingin Anda lakukan untuk muatan besar), Java 9 memperkenalkan: 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());
}

Untuk mengurai JSON menggunakan perpustakaan GSON, misalnya

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

Berikut ini contoh lengkap cara mem-parsing konten Json. Contohnya mengambil statistik versi Android (ditemukan dari kode sumber Android Studio di sini , yang terhubung ke sini ).

Salin file "distributions.json" yang Anda dapatkan dari sana ke res / raw, sebagai cadangan.

build.gradle

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

nyata

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

Sebagai alternatif dari ketergantungan, Anda juga dapat menggunakan ini sebagai gantinya:

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

dan mundur:

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

Hasil menjalankan ini:

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%
pengembang android
sumber