Самый простой способ прочитать JSON с URL в Java

246

Это может быть глупый вопрос, но как проще всего читать и анализировать JSON из URL в Java ?

В Groovy это всего лишь несколько строк кода. Примеры Java, которые я нахожу, смехотворно длинные (и имеют огромный блок обработки исключений).

Все, что я хочу сделать, это прочитать содержание этой ссылки .

Помпоний
источник
9
Обработка исключений требуется, поскольку Java заставляет вас обрабатывать любые объявленные исключения. Что не так с обработкой исключений?
Фальмарри
3
Ну, «Ява заставит тебя» - самая большая проблема
Джонатан Клотье
9
Если бы Java не заставлял вас обрабатывать исключения, как вы думаете, программы все равно будут работать и работать хорошо? Что, если меня попросят ввести мой возраст в программу, и в качестве входных данных я предоставлю snarfleblagger? Должен ли Java разрешать выполнение программы без проблем? Если вы не хотите обрабатывать исключения, объявите их как вызываемые методами, в которых они могут возникать, и наблюдайте, как ваша программа перестала работать, когда что-то не так.
Ричард Баркер
2
Совсем не глупый вопрос. Особенно из PHP, где вы можете сделать это json_decode(file_get_contents($url));и быть готовым!
dtbarne

Ответы:

195

Используя артефакт 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.
Кдабир
7
Зачем? Затем readLineфункция выполнит цикл, и мне придется объединять строки вместо символов, что дороже. Это не сделает код таким коротким, как сейчас. Кроме того, в нотации JSON нет понятия «линии», так почему я должен читать их как таковые?
Роланд Иллиг
4
Рассмотрим IOUtils.toString(InputStream)метод Apache commons-io . Это должно избавить вас от некоторых линий и ответственности.
Марк Тилеманс
3
Почему я получаю эту ошибку «Конструктор JSONObject (String) не определен» в строке JSONObject json = new JSONObject (jsonText); в методе "readJsonFromUrl" ..? @RolandIllig
Karthick pop
2
С GSON, Jackson, Boon, Genson и другими вам нужно только указать источник: либо просто 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; это, возможно, было первым делом, но есть полдюжины лучших альтернатив, так что причин для его использования очень мало.

StaxMan
источник
Что здесь URL? Это строка или объект URL или байт []?
Динеш
1
Я имел в виду , java.net.URLно ни один работает, а также множество других источников ( File, InputStream, Reader, String).
StaxMan
4
В приведенном выше примере это должен быть java.net.URL, в противном случае он попытается проанализировать строку 'http: // ....' как json, что приведет к ошибке
zbstof
@ Зотов Да. Передача Stringпотребует, чтобы содержимое было в формате JSON, а не текстовое кодирование URI / URL для использования.
StaxMan
2
Нераспознанный токен «https»: ожидалось («истина», «ложь» или «
ноль
60

Самый простой способ: использовать gson, собственную библиотеку goto json от 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
user2654569
источник
1
Почему я получаю сообщение об ошибке NetworkOnMainThreadException? Я должен использовать AsyncTask или есть другой способ? В этом примере вы тоже получили эту ошибку?
Бенец
Опечатка, должно быть:rootobj.get("zip_code").getAsString();
loopasam
Как импортировать jsonParser? Я всегда получаю сообщение об ошибке: «Ошибка: (69, 9) ошибка: не удается найти класс символов JsonParser»
MAESTRO_DE
1
Добавьте maven dependency <dependency> <groupId> com.google.code.gson </ groupId> <artifactId> gson </ artifactId> <версия> 2.8.0 </ version> </ dependency>, чтобы получить JsonParse в вашем pom файл.
sashikanta
может быть упрощен и обработан безопасным способом с помощью Gson, например: MyResponseObject response = new GsonBuilder (). create (). fromJson (new InputStreamReader ((InputStream) request.getContent ()), MyResponseObject.class);
Грегор
42

Если вы не возражаете против использования пары библиотек, это можно сделать в одну строку.

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

JSONObject json = new JSONObject(IOUtils.toString(new URL("https://graph.facebook.com/me"), Charset.forName("UTF-8")));
ezwrighter
источник
Есть ли у вас какие-либо предположения о том, почему добавление зависимости в gradle не позволит установить это приложение на мой 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 библиотеки Facebook API. У меня нет никакого опыта в этой области, но есть вопрос переполнения стека, связанный с использованием API Facebook в 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, вы просто вызываете этот класс и метод в вашем классе Activity

мой код здесь

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

С помощью jersey-client очень просто включить эту зависимость 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);

Затем используйте Google Gson для анализа JSON:

Gson gson = new Gson();
Type gm = new TypeToken<CoinDeskMessage>() {}.getType();
CoinDeskMessage cdm = gson.fromJson(json, gm);
user3892260
источник
Ничего против ответа, но так много проблем с пакетом jersey-client ... это куча ошибок.
Джонни Бигуд
Я не сталкивался с какими-либо проблемами. Можете ли вы указать на некоторые особенности и / или альтернативы?
user3892260
Проблемы, которые я обнаружил, были связаны с ошибкой, не найденной в классе, я не был точно уверен в ее причине, потому что мне не удалось ее исправить.
Джонни Бигуд
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");
            }


   }
Mastercool
источник
Вы получили исключение 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.
kdabir
источник
0

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

Для извлечения JSON из URL-адреса это, по-видимому, самый простой способ с использованием строго классов JDK (но, вероятно, это не то, что вы хотели бы делать для больших полезных нагрузок), Java 9 представила: https://docs.oracle.com/en/ Java / JavaSE / 11 / документы / 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 студии здесь , который отображает ссылку здесь ).

Скопируйте полученный вами оттуда файл "Distribution.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%
разработчик Android
источник