moyen le plus simple de lire json à partir d'une URL en java

245

Cela peut être une question stupide, mais quelle est la façon la plus simple de lire et d'analyser JSON à partir d'une URL en Java ?

Dans Groovy, il s'agit de quelques lignes de code. Les exemples Java que je trouve sont ridiculement longs (et ont un énorme bloc de gestion des exceptions).

Tout ce que je veux faire, c'est lire le contenu de ce lien .

Pomponius
la source
9
La gestion des exceptions est requise car java vous oblige à gérer toutes les exceptions déclarées. Quel est le problème avec la gestion des exceptions?
Falmarri
3
eh bien, la "java force you" est le plus gros problème
Jonatan Cloutier
9
Si java ne vous a pas forcé à gérer les exceptions, pensez-vous que les programmes continueraient de bien fonctionner? Et si on me demandait d'entrer mon âge dans un programme et que je donnais snarfleblagger comme entrée? Java doit-il permettre au programme de s'exécuter sans problème? Si vous ne voulez pas gérer les exceptions, déclarez-les comme étant levées par les méthodes dans lesquelles elles peuvent se produire et regardez votre programme échouer lorsque quelque chose ne va pas parfaitement.
Richard Barker
2
Pas une question stupide du tout. Surtout venant de PHP où vous pouvez le faire json_decode(file_get_contents($url));et être fait!
dtbarne

Réponses:

193

En utilisant l'artefact Maven, org.json:jsonj'ai obtenu le code suivant, qui je pense est assez court. Pas aussi court que possible, mais toujours utilisable.

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
la source
3
au lieu de lire caractère par caractère, vous pouvez utiliser readLine () sur BufferedReader. Cela réduira le nombre d'itérations de la boucle while.
kdabir
6
Pourquoi? La readLinefonction fera alors la boucle, et je dois concaténer les lignes au lieu des caractères, ce qui est plus cher. Cela ne garderait pas le code aussi court qu'il l'est actuellement. De plus, en notation JSON il n'y a pas de concept de "lignes", alors pourquoi devrais-je les lire comme telles?
Roland Illig
4
Considérez la IOUtils.toString(InputStream)méthode d' Apache commons-io . Cela devrait vous épargner quelques lignes et responsabilités.
Mark Tielemans
3
Pourquoi j'obtiens cette erreur "Le constructeur JSONObject (String) n'est pas défini" dans la ligne de JSONObject json = new JSONObject (jsonText); dans la méthode "readJsonFromUrl" ..? @RolandIllig
Karthick pop
2
Avec GSON, Jackson, Boon, Genson et autres, il vous suffit d'alimenter la source: soit simplement l'URL, soit tout au plus InputStream. Bien que le code ci-dessus puisse être court à org.jsonutiliser, assurez-vous de vérifier les autres bibliothèques disponibles - il n'est pas nécessaire d'écrire plus de 1 à 3 lignes de code pour cette tâche.
StaxMan
68

Voici quelques versions alternatives avec Jackson (car il existe plusieurs façons de vouloir des données):

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

Et en particulier le cas habituel (IMO) où vous souhaitez traiter des objets Java, peut être réalisé sur une seule ligne:

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

D'autres bibliothèques comme Gson prennent également en charge les méthodes à une ligne; pourquoi de nombreux exemples montrent des sections beaucoup plus longues est étrange. Et pire encore, de nombreux exemples utilisent la bibliothèque org.json obsolète; cela a peut-être été la première chose à faire, mais il existe une demi-douzaine de meilleures alternatives, il n'y a donc que très peu de raisons de l'utiliser.

StaxMan
la source
Qu'est-ce que l'URL ici? S'agit-il d'une chaîne ou d'un objet URL ou d'un octet []?
Dinesh
1
Je pensais , java.net.URLmais soit on travaille, ainsi que beaucoup d'autres sources ( File, InputStream, Reader, String).
StaxMan
4
Il devrait être java.net.URL dans l'exemple ci-dessus, sinon il essaiera d'analyser la chaîne 'http: // ....' en tant que json, ce qui
générera
@Zotov Oui. Pour passer, il Stringfaudrait que le contenu soit JSON et non le codage textuel de l'URI / URL à utiliser.
StaxMan
2
Jeton non reconnu 'https': attendait ('vrai', 'faux' ou 'nul')
Damir Olejar
60

La manière la plus simple: utilisez gson, la propre bibliothèque goto json de google. https://code.google.com/p/google-gson/

Voici un exemple. Je vais sur ce site Web de géolocalisation gratuit et j'analyse le json et affiche mon code postal. (il suffit de mettre ce truc dans une méthode principale pour le tester)

    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
la source
1
Pourquoi j'obtiens l'erreur «NetworkOnMainThreadException»? Je dois utiliser un AsyncTask ou il existe un autre moyen? Dans cet exemple, avez-vous également obtenu cette erreur?
Benetz
Typo, devrait être:rootobj.get("zip_code").getAsString();
loopasam
Comment importer le jsonParser? J'obtiens toujours l'erreur: «Erreur: (69, 9) erreur: impossible de trouver la classe de symboles JsonParser»
MAESTRO_DE
1
Veuillez ajouter la dépendance maven <dependency> <groupId> com.google.code.gson </groupId> <artifactId> gson </artifactId> <version> 2.8.0 </version> </dependency> pour obtenir le JsonParse dans votre pom fichier.
sashikanta
peut être simplifié et géré de manière sécurisée avec Gson comme: MyResponseObject response = new GsonBuilder (). create (). fromJson (new InputStreamReader ((InputStream) request.getContent ()), MyResponseObject.class); MyResponseObject.class);
Gregor
42

Si cela ne vous dérange pas d'utiliser quelques bibliothèques, cela peut être fait sur une seule ligne.

Inclut les bibliothèques Apache Commons IOUtils et json.org .

JSONObject json = new JSONObject(IOUtils.toString(new URL("https://graph.facebook.com/me"), Charset.forName("UTF-8")));
ezwrighter
la source
Avez-vous une idée de la raison pour laquelle l'ajout de la dépendance au gradle empêcherait l'installation de cette application sur mon Google Pixel XL?
andrdoiddev
@andrdoiddev - Vous devriez poser cela comme une question distincte. Il est plus général pour Apache Commons, Gradle et Android Development.
ezwrighter
1
C'est assez ancien maintenant, mais c'est toujours une bonne solution, donc juste au cas où @andrdoiddev ou quelqu'un d'autre aurait encore besoin des dépendances Gradle, ce sont celles que j'utilise: groupe de compilation: 'org.json', nom: 'json ', version:' 20180813 'groupe de compilation:' commons-io ', nom:' commons-io ', version:' 2.6 '
r02
Supposons que vous exécutez plusieurs requêtes, enregistrez les réponses json dans un JSONArray, puis écrivez le JSONArray dans un fichier à l'aide de FileWriter, cette bibliothèque n'échappe pas aux guillemets doubles. Cela permet au fichier d'être facilement analysé vers JSONArray.
Gh0sT
6

Utilisez HttpClient pour récupérer le contenu de l'URL. Et puis utilisez la bibliothèque de json.org pour analyser le JSON. J'ai utilisé ces deux bibliothèques sur de nombreux projets et elles ont été robustes et simples à utiliser.

En dehors de cela, vous pouvez essayer d'utiliser une bibliothèque Java Facebook API. Je n'ai aucune expérience dans ce domaine, mais il y a une question sur le débordement de pile lié à l' utilisation d'une API Facebook en Java . Vous voudrez peut-être considérer RestFB comme un bon choix pour une bibliothèque à utiliser.

Jon Snyder
la source
5

J'ai fait l'analyseur json de la manière la plus simple, le voici

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;

}
}

cette classe renvoie l'objet json de l'url

et quand vous voulez l'objet json, vous appelez simplement cette classe et la méthode dans votre classe Activity

mon code est ici

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

ici la "clé json" est dénotée que la clé dans votre fichier json

ceci est un simple exemple de fichier json

{
    "json":"hi"
}

Ici, "json" est la clé et "hi" est la valeur

Cela obtiendra votre valeur json pour le contenu de la chaîne.

Ribin Das
la source
1
Je pense que ce n'est pas le "moyen le plus simple"
stand alone le
3

C'est très simple, en utilisant jersey-client, il suffit d'inclure cette dépendance maven:

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

Ensuite, invoquez-le en utilisant cet exemple:

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

Utilisez ensuite le Gson de Google pour analyser le JSON:

Gson gson = new Gson();
Type gm = new TypeToken<CoinDeskMessage>() {}.getType();
CoinDeskMessage cdm = gson.fromJson(json, gm);
user3892260
la source
Rien contre la réponse, mais tant de problèmes avec le package jersey-client ... c'est un gâchis d'erreurs.
Johnny Bigoode
je n'ai rencontré aucun problème avec. pouvez-vous indiquer quelques détails et / ou alternatives?
user3892260
Les problèmes que j'ai trouvés étaient liés à une erreur non trouvée, je n'étais pas exactement sûr de la cause, car je n'ai pas réussi à le résoudre.
Johnny Bigoode
3

J'ai trouvé que c'était de loin le moyen le plus simple.

Utilisez cette méthode:

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

Et utilisez-le comme ceci:

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
la source
Vous avez une exception ClassCastException assise là-dedans. Modifiez l'URL de la ligne u = nouvelle URL (url); vers cette URL u = nouvelle URL (null, url, new sun.net.www.protocol.https.Handler ()); pour que ce code fonctionne
arya ensoleillé
2

Je ne sais pas si cela est efficace, mais c'est l'une des manières possibles:

Lire json à partir de l'url url.openStream()et lire le contenu dans une chaîne.

construire un objet JSON avec cette chaîne (plus sur json.org )

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

Je voulais ajouter une réponse mise à jour ici, car les mises à jour récentes (quelque peu) du JDK ont facilité la lecture du contenu d'une URL HTTP. Comme d'autres l'ont dit, vous devrez toujours utiliser une bibliothèque JSON pour effectuer l'analyse, car le JDK n'en contient pas actuellement. Voici quelques-unes des bibliothèques JSON les plus couramment utilisées pour Java:

Pour récupérer JSON à partir d'une URL, cela semble être le moyen le plus simple d'utiliser strictement des classes JDK (mais probablement pas quelque chose que vous voudriez faire pour de grandes charges utiles), Java 9 a introduit: 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());
}

Pour analyser le JSON à l'aide de la bibliothèque GSON, par exemple

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

Voici un échantillon complet de la façon d'analyser le contenu Json. L'exemple prend les statistiques des versions d'Android (trouvées à partir du code source d'Android Studio ici , qui renvoie à ici ).

Copiez le fichier "distributions.json" que vous obtenez à partir de là dans res / raw, comme solution de rechange.

build.gradle

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

manifeste

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

Comme alternative à la dépendance, vous pouvez également l'utiliser à la place:

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

et le repli:

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

Le résultat de l'exécution de ceci:

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%
développeur android
la source