2011-06-28 22 views
46

używam java zadzwonić url, która zwraca obiekt JSON:Jak analizować JSON strumień wejściowy

url = new URL("my URl"); 
urlInputStream = url.openConnection().getInputStream(); 

Jak mogę przekonwertować odpowiedź na formę smyczkową i analizować je?

+0

Witamy w przepełnieniu stosu! pamiętaj, aby poprawnie sformatować swój kod podczas publikowania pytań. –

Odpowiedz

6

użycie Jackson przekonwertować json strumień wejściowy do mapy lub obiektu http://jackson.codehaus.org/

istnieją również inne biblioteki przydatne dla JSON, można google: json java

+8

proszę poprawić tę odpowiedź z przykładami dla każdej biblioteki – Jayen

+0

Zaktualizowany link do Jacksona https://github.com/FasterXML/jackson – disrvptor

+0

To w zasadzie nic nie wyjaśnia. –

4

korzystać z biblioteki.

  • GSON
  • Jackson
  • lub jedną z wielu innych bibliotek JSON, które są tam.
-3
{ 
    InputStream is = HTTPClient.get(url); 
    InputStreamReader reader = new InputStreamReader(is); 
    JSONTokener tokenizer = new JSONTokener(reader); 
    JSONObject jsonObject = new JSONObject(tokenizer); 
} 
+3

Czy JSONTokener nie wymaga łańcucha JSON, a nie InputStreamReader? – VMcPherron

+4

[link] (http://developer.android.com/reference/org/json/JSONTokener.html) Wskazuje, że dla systemu Android JSONTokener pobiera tylko ciąg. – VMcPherron

76

Proponuję trzeba użyć czytnika do konwertowania InputStream w

BufferedReader streamReader = new BufferedReader(new InputStreamReader(in, "UTF-8")); 
StringBuilder responseStrBuilder = new StringBuilder(); 

String inputStr; 
while ((inputStr = streamReader.readLine()) != null) 
    responseStrBuilder.append(inputStr); 
new JSONObject(responseStrBuilder.toString()); 

Próbowałem in.toString(), ale zwraca.

getClass().getName() + '@' + Integer.toHexString(hashCode()) 

(jak dokumentacja mówi, że wywodzi się z toString z Object)

+1

Jeśli wydajność jest kwestią problemową, domyślna pojemność StringBuilder to 16 znaków, możesz ją zwiększyć, używając długości większej niż średnia długość tekstu, na przykład 'new StringBuilder (2048)'. Czytanie linii po linii prawdopodobnie nie jest najlepsze dla wydajności. –

+0

U uratowałem mi życie, lol tnx – vinidog

5

Dla tych t zwrócił uwagę na fakt, że nie można użyć metody toString InputStream takiego zobaczyć https://stackoverflow.com/a/5445161/1304830:

Moja prawidłowa odpowiedź byłaby wówczas:

import org.json.JSONObject; 

public static String convertStreamToString(java.io.InputStream is) { 
    java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A"); 
    return s.hasNext() ? s.next() : ""; 
} 

... 

JSONObject json = new JSONObject(convertStreamToString(url.openStream()); 
+2

Konwersja strumienia na ciąg wymaga posiadania całej zawartości w pamięci, gdzie jako strumień nie byłoby. –

+1

Mimo że może to być duża pamięć, ta metoda zasługuje na kilka punktów, ponieważ dla małych obiektów JSON jest bardzo wyraźna i zwarta –

21

Wszystkie aktualne odpowiedzi założyć, że jest w porządku, aby wyciągnąć cały JSON do pamięci, gdzie zaletą InputStream jest to, że możesz czytać dane wejściowe po trochu. Jeśli nie chcesz od razu czytać całego pliku Json, sugerowałbym korzystanie z biblioteki Jacksona (która jest moją ulubioną, ale jestem pewien, że inni, jak Gson, mają podobne funkcje).

Z Jacksonem możesz użyć JsonParser do czytania jednej sekcji na raz. Poniżej znajduje się przykład kodu, który napisałem, który otacza czytanie tablicy JsonObjects w Iteratorze. Jeśli chcesz zobaczyć przykład Jacksona, spójrz na metody initJsonParser, initFirstElement i initNextObject.

public class JsonObjectIterator implements Iterator<Map<String, Object>>, Closeable { 
    private static final Logger LOG = LoggerFactory.getLogger(JsonObjectIterator.class); 

    private final InputStream inputStream; 
    private JsonParser jsonParser; 
    private boolean isInitialized; 

    private Map<String, Object> nextObject; 

    public JsonObjectIterator(final InputStream inputStream) { 
     this.inputStream = inputStream; 
     this.isInitialized = false; 
     this.nextObject = null; 
    } 

    private void init() { 
     this.initJsonParser(); 
     this.initFirstElement(); 
     this.isInitialized = true; 
    } 

    private void initJsonParser() { 
     final ObjectMapper objectMapper = new ObjectMapper(); 
     final JsonFactory jsonFactory = objectMapper.getFactory(); 

     try { 
      this.jsonParser = jsonFactory.createParser(inputStream); 
     } catch (final IOException e) { 
      LOG.error("There was a problem setting up the JsonParser: " + e.getMessage(), e); 
      throw new RuntimeException("There was a problem setting up the JsonParser: " + e.getMessage(), e); 
     } 
    } 

    private void initFirstElement() { 
     try { 
      // Check that the first element is the start of an array 
      final JsonToken arrayStartToken = this.jsonParser.nextToken(); 
      if (arrayStartToken != JsonToken.START_ARRAY) { 
       throw new IllegalStateException("The first element of the Json structure was expected to be a start array token, but it was: " + arrayStartToken); 
      } 

      // Initialize the first object 
      this.initNextObject(); 
     } catch (final Exception e) { 
      LOG.error("There was a problem initializing the first element of the Json Structure: " + e.getMessage(), e); 
      throw new RuntimeException("There was a problem initializing the first element of the Json Structure: " + e.getMessage(), e); 
     } 

    } 

    private void initNextObject() { 
     try { 
      final JsonToken nextToken = this.jsonParser.nextToken(); 

      // Check for the end of the array which will mean we're done 
      if (nextToken == JsonToken.END_ARRAY) { 
       this.nextObject = null; 
       return; 
      } 

      // Make sure the next token is the start of an object 
      if (nextToken != JsonToken.START_OBJECT) { 
       throw new IllegalStateException("The next token of Json structure was expected to be a start object token, but it was: " + nextToken); 
      } 

      // Get the next product and make sure it's not null 
      this.nextObject = this.jsonParser.readValueAs(new TypeReference<Map<String, Object>>() { }); 
      if (this.nextObject == null) { 
       throw new IllegalStateException("The next parsed object of the Json structure was null"); 
      } 
     } catch (final Exception e) { 
      LOG.error("There was a problem initializing the next Object: " + e.getMessage(), e); 
      throw new RuntimeException("There was a problem initializing the next Object: " + e.getMessage(), e); 
     } 
    } 

    @Override 
    public boolean hasNext() { 
     if (!this.isInitialized) { 
      this.init(); 
     } 

     return this.nextObject != null; 
    } 

    @Override 
    public Map<String, Object> next() { 
     // This method will return the current object and initialize the next object so hasNext will always have knowledge of the current state 

     // Makes sure we're initialized first 
     if (!this.isInitialized) { 
      this.init(); 
     } 

     // Store the current next object for return 
     final Map<String, Object> currentNextObject = this.nextObject; 

     // Initialize the next object 
     this.initNextObject(); 

     return currentNextObject; 
    } 

    @Override 
    public void close() throws IOException { 
     IOUtils.closeQuietly(this.jsonParser); 
     IOUtils.closeQuietly(this.inputStream); 
    } 

} 

Jeśli nie dbają o zużycie pamięci, to z pewnością byłoby łatwiejsze do odczytania całego pliku i przetwarza je jako jeden duży Json jak wspomniano w innych odpowiedzi.

2

Jeśli chcesz użyć Jackson Databind (co Spring wykorzystuje domyślnie dla jego HttpMessageConverters), a następnie można użyć ObjectMapper.readTree(InputStream) API. Na przykład:

ObjectMapper mapper = new ObjectMapper(); 
JsonNode json = mapper.readTree(myInputStream); 
Powiązane problemy