найпростіший спосіб прочитати json з URL-адреси в Java


245

Це може бути німим питанням, але який найпростіший спосіб прочитати та розібрати JSON з URL-адреси на Java ?

У Groovy це справа кількох рядків коду. Приклади Java, які я вважаю, смішно довгі (і мають величезний блок обробки винятків).

Все, що я хочу зробити, - це прочитати зміст цього посилання .


9
Обробка винятків необхідна, оскільки java змушує вас обробляти будь-які оголошені виключення. Що не так з обробкою виключень?
Falmarri

3
Що ж, "java force you" - це найбільша проблема
Jonatan Cloutier

9
Якщо java не змусило вас обробляти винятки, чи вважаєте ви, що програми все-таки запускатимуться та працюватимуть добре? Що робити, якщо мене попросять ввести свій вік у програму, і я дав snarfleblagger як свій внесок? Чи повинен java дозволяти програмі просто виконувати без проблем? Якщо ви не хочете обробляти винятки, тоді оголосьте, що вони кинуті методами, які вони можуть виникнути, і спостерігайте за тим, як ваша програма виходить з ладу, коли щось не зовсім правильне.
Річард Баркер

2
Зовсім не тупе питання. Особливо з PHP, де ви можете це зробити json_decode(file_get_contents($url));і зробити!
dtbarne

Відповіді:


193

Використовуючи артефакт Maven, org.json:jsonя отримав наступний код, який, на мою думку, є досить коротким. Не найкоротший, але все-таки корисний.

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
замість того, щоб читати символ за символом, ви можете використовувати readLine () на BufferedReader. Це зменшить кількість ітерацій циклу while.
kdabir

6
Для чого? Тоді readLineфункція зробить цикл, і мені доведеться об'єднати рядки замість символів, що дорожче. Це не призведе до того, що код буде таким коротким, як зараз. Крім того, у позначенні JSON немає поняття "рядки", тож чому я повинен читати їх як такі?
Роланд Ілліг

4
Розглянемо IOUtils.toString(InputStream)метод Apache commons-io . Це повинно економити певні лінії та відповідальність.
Марк Тілеманс

3
Чому я отримую цю помилку "Конструктор JSONObject (String) не визначений" у рядку JSONObject json = new JSONObject (jsonText); у методі "readJsonFromUrl" ..? @RolandIllig
Karthick pop

2
Що стосується GSON, Джексона, Буна, Генсона та інших, вам потрібно лише годувати джерело: або лише URL-адресу, або максимум InputStream. Хоча код вище може бути org.jsonнедоступним для використання, переконайтеся, що перевірити інші наявні вкладки - для цього завдання не потрібно писати більше 1-3 рядків коду.
StaxMan

68

Ось кілька альтернативних версій з Джексоном (оскільки існує декілька способів, як вам можуть захотіти дані):

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

А конкретно для звичайного випадку (IMO), коли ви хочете мати справу з об’єктами Java, можна зробити один вкладиш:

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

Інші гібриди, як Gson, також підтримують однолінійні методи; чому багато прикладів показують набагато довші розділи, це не дивно. А ще гірше - багато прикладів використовують застарілу бібліотеку org.json; це, можливо, було перше, але є півдесятка кращих альтернатив, тому є дуже мало причин використовувати його.


Що тут URL? Це рядок або URL-об’єкт чи байт []?
Дінеш

1
Я мав у виду , java.net.URLале жоден працює, а також безліч інших джерел ( File, InputStream, Reader, String).
StaxMan

4
У прикладі вище, це має бути java.net.URL, інакше він спробує проаналізувати рядок 'http: // ....' як json, що призведе до помилки
zbstof

@Zotov Так. Для передачі Stringнеобхідний вміст бути JSON, а не текстове кодування URI / URL для використання.
StaxMan

2
Нерозпізнаний жетон "https": очікував ("правда", "
помилка

60

Найпростіший спосіб: використовувати власну бібліотеку goto json у gson, google. https://code.google.com/p/google-gson/

Ось зразок. Я заходжу на цей безкоштовний веб-сайт геолокатора і аналізую json та показую свій поштовий індекс. (просто поставте цей матеріал в основний метод, щоб перевірити його)

    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
Чому я отримую помилку "NetworkOnMainThreadException"? Я повинен користуватися AsyncTask чи є інший спосіб? У цьому прикладі ви також отримали цю помилку?
Бенець

Друкарська помилка, повинна бути:rootobj.get("zip_code").getAsString();
loopasam

Як я імпортую jsonParser? Я завжди отримую помилку: 'Помилка: (69, 9) помилка: не вдається знайти символ символу JsonParser'
MAESTRO_DE

1
Додайте залежність maven <dependency> <groupId> com.google.code.gson </groupId> <artifactId> gson </artifactId> <version> 2.8.0 </version> </dependency>, щоб отримати JsonParse у вашій пам’яті файл.
сашиканта

можна спростити та обробляти в безпечному вигляді за допомогою Gson, наприклад: MyResponseObject response = новий GsonBuilder (). create (). fromJson (новий InputStreamReader ((InputStream) request.getContent ()), MyResponseObject.class);
Грегор

42

Якщо ви не проти використовувати пару бібліотек, це можна зробити в одному рядку.

Включити бібліотеки AOche Commons IOUtils & json.org .

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

Чи маєте ви здогадки про те, чому додавання залежності до градації не дозволить встановити цей додаток на моєму Google Pixel XL?
andrdoiddev

@andrdoiddev - Вам слід задати це окремо. Він більш загальний для Apache Commons, Gradle та Android Development.
ezwrighter

1
Зараз це вже досить старе, але все-таки хороше рішення, тому на всякий випадок @andrdoiddev або хтось ще потребує залежностей від Gradle, це ті, якими я користуюся: compile group: 'org.json', name: 'json ', версія:' 20180813 'група компіляції:' commons-io ', назва:' commons-io ', версія:' 2.6 '
r02

Скажімо, ви запускаєте кілька запитів, зберігаючи відповіді json на JSONArray, а потім записуєте JSONArray у файл за допомогою FileWriter, тоді ця бібліотека НЕ ​​ВКАЗВАЄ подвійних лапок. Це робить файл легко проаналізований назад до JSONArray.
Gh0sT

6

Використовуйте HttpClient, щоб захопити вміст URL-адреси. А потім використовуйте бібліотеку з json.org для розбору JSON. Я використовував ці дві бібліотеки у багатьох проектах, і вони були надійними та простими у використанні.

Крім того, ви можете спробувати скористатися Java-бібліотекою API API. Я не маю жодного досвіду роботи в цій області, але виникає питання щодо переповнення стека, пов’язаного з використанням Facebook API в Java . Ви можете розглянути RestFB як хороший вибір бібліотеки для використання.


5

Я зробив аналізатор json найпростішим способом, ось він

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;

}
}

цей клас повертає об’єкт json з URL

і коли ви хочете об’єкт json, ви просто викликаєте цей клас та метод у вашому класі активності

мій код тут

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

тут "ключ json" позначається, що ключ у вашому файлі json

це простий приклад файлу json

{
    "json":"hi"
}

Тут "json" є ключовим, а "привіт" - значенням

Це отримає ваше значення json для рядкового вмісту.


1
Я думаю, що це не "найпростіший спосіб"
самостійно

3

За допомогою джерсі-клієнта це дуже просто, просто включіть цю залежність від Maven:

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

Потім викликайте його, використовуючи цей приклад:

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

Потім використовуйте Gson Google для розбору JSON:

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

Нічого проти відповіді, але стільки проблем із пакетом jersey-client ... це безлад помилок.
Джонні Бігуд

я не стикався з цим жодних проблем. Ви можете вказати на деякі специфіки та / або альтернативи?
користувач3892260

Проблеми, які я знайшов, стосувалися помилки classnotfound, не були точно впевнені в причині, тому що мені не вдалося її виправити.
Джонні Бігуд

3

На сьогоднішній день я вважаю це найпростішим способом.

Використовуйте цей метод:

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

І використовуйте його так:

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


   }

У вас сидить виняток ClassCastException. Змініть URL-адресу рядка u = нова URL-адреса (URL-адреса); до цієї URL u = нова URL (null, url, new sun.net.www.protocol.https.Handler ()); щоб цей код працював
сонячна арія

2

Я не впевнений, чи ефективно це, але це один із можливих способів:

Прочитайте json з використання URL-адреси url.openStream()та прочитайте вміст у рядку.

побудувати об’єкт JSON за допомогою цього рядка (докладніше на json.org )

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

0

Я хотів додати тут оновлену відповідь, оскільки (дещо) останні оновлення до JDK полегшили читання вмісту URL-адреси HTTP. Як вже говорили інші, вам все одно потрібно буде використовувати бібліотеку JSON для розбору, оскільки JDK наразі не містить його. Ось декілька найбільш часто використовуваних бібліотек JSON для Java:

Щоб отримати JSON з URL-адреси, це здається найпростішим способом, використовуючи строго JDK-класи (але, мабуть, це не те, що ви хочете зробити для великих корисних навантажень), Java 9 представила: https://docs.oracle.com/uk/ 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());
}

Для розбору JSON, наприклад, за допомогою бібліотеки GSON

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

0

Ось повний зразок розбору вмісту Json. Виконується статистика версій Android (знайдено з вихідного коду Android студії тут , які посилання тут ).

Скопіюйте файл "distributions.json", який ви отримаєте звідти, у res / raw, як резервний.

build.gradle

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

маніфест

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

Як альтернативу залежності ви можете також використовувати це замість:

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

і резервний:

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

Результат виконання цього:

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%
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.