如何解析JSON输入流

时间:2011-06-28 19:13:05

标签: java android json

我使用java来调用返回JSON对象的url:

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

如何将响应转换为字符串形式并解析它?

11 个答案:

答案 0 :(得分:78)

我建议你必须使用Reader来转换你的InputStream。

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

我尝试了in.toString()但它返回:

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

(就像文档说它从Object派生到toString)

答案 1 :(得分:26)

所有当前的答案都假设可以将整个JSON拉入内存,其中InputStream的优点是您可以一点一点地读取输入。如果你想避免一次阅读整个Json文件,那么我建议使用Jackson库(这是我个人的最爱,但我确信像Gson这样的其他人也有类似的功能)。

使用Jackson,您可以使用JsonParser一次读取一个部分。下面是我编写的代码示例,它包含了在Iterator中读取JsonObjects数组的内容。如果您只想查看Jackson的示例,请查看initJsonParser,initFirstElement和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);
    }

}

如果您不关心内存使用情况,那么读取整个文件并将其解析为其他答案中提到的一个大Json肯定会更容易。

答案 2 :(得分:6)

使用jackson将json输入流转换为地图或对象http://jackson.codehaus.org/

还有一些其他有用的json库,你可以google:json java

答案 3 :(得分:6)

对于那些指出你不能像这样使用InputStream的toString方法的事实,请参阅https://stackoverflow.com/a/5445161/1304830

我的正确答案是:

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

答案 4 :(得分:4)

使用图书馆。

答案 5 :(得分:3)

如果您想使用Jackson DatabindSpring默认使用HttpMessageConverters),那么您可以使用ObjectMapper.readTree(InputStream) API。例如,

ObjectMapper mapper = new ObjectMapper();
JsonNode json = mapper.readTree(myInputStream);

答案 6 :(得分:2)

科特林版和Gson

读取响应JSON:

val response = BufferedReader(
                   InputStreamReader(conn.inputStream, "UTF-8")
               ).use { it.readText() }

我们可以使用Gson来解析响应:

val model = Gson().fromJson(response, YourModelClass::class.java)

答案 7 :(得分:0)

如果您有JSON文件,则可以在资产文件夹中进行设置,然后使用此代码进行调用

InputStream in = mResources.getAssets().open("fragrances.json"); 
// where mResources object from Resources class

答案 8 :(得分:0)

此示例从对象流中读取所有对象, 假定您需要CustomObjects而不是Map:

        ObjectMapper mapper = new ObjectMapper();
        JsonParser parser = mapper.getFactory().createParser( source );
        if(parser.nextToken() != JsonToken.START_ARRAY) {
          throw new IllegalStateException("Expected an array");
        }
        while(parser.nextToken() == JsonToken.START_OBJECT) {
          // read everything from this START_OBJECT to the matching END_OBJECT
          // and return it as a tree model ObjectNode
          ObjectNode node = mapper.readTree(parser);
          CustomObject custom = mapper.convertValue( node, CustomObject.class );
           // do whatever you need to do with this object
          System.out.println( "" + custom );
        }
        parser.close();

此答案是通过使用Use Jackson To Stream Parse an Array of Json ObjectsConvert JsonNode into Object

组成的

答案 9 :(得分:0)

我建议使用javax.json.Json工厂作为不太详细的可能解决方案:

JsonObject json = Json.createReader(yourInputStream).readObject();

享受!

答案 10 :(得分:-3)

{
    InputStream is = HTTPClient.get(url);
    InputStreamReader reader = new InputStreamReader(is);
    JSONTokener tokenizer = new JSONTokener(reader);
    JSONObject jsonObject = new JSONObject(tokenizer);
}