Java 如何解析 JSON 输入流

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6511880/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 06:29:52  来源:igfitidea点击:

How to parse a JSON Input stream

javaandroidjson

提问by Ritesh Mehandiratta

I am using java to call a url that returns a JSON object:

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

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

How can I convert the response into string form and parse it?

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

回答by Penkov Vladimir

use Hymanson to convert json input stream to the map or object http://Hymanson.codehaus.org/

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

there are also some other usefull libraries for json, you can google: json java

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

回答by Dunes

Use a library.

使用图书馆。

  • GSON
  • Hymanson
  • or one of many other JSON libraries that are out there.

回答by Sudhir Bhojwani

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

回答by Martin Christmann

I would suggest you have to use a Reader to convert your InputStream in.

我建议您必须使用 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());

I tried in.toString() but it returns:

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

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

(like documentation says it derives to toString from Object)

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

回答by Fr4nz

For those that pointed out the fact that you can't use the toString method of InputStream like this see https://stackoverflow.com/a/5445161/1304830:

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

My correct answer would be then :

我的正确答案是:

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

回答by BoostHungry

All the current answers assume that it is okay to pull the entire JSON into memory where the advantage of an InputStream is that you can read the input little by little. If you would like to avoid reading the entire Json file at once then I would suggest using the Hymanson library (which is my personal favorite but I'm sure others like Gson have similar functions).

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

With Hymanson you can use a JsonParser to read one section at a time. Below is an example of code I wrote that wraps the reading of an Array of JsonObjects in an Iterator. If you just want to see an example of Hymanson, look at the initJsonParser, initFirstElement, and initNextObject methods.

使用 Hymanson,您可以使用 JsonParser 一次读取一个部分。下面是我编写的代码示例,该示例将读取 JsonObjects 数组的内容包装在迭代器中。如果您只想查看 Hymanson 的示例,请查看 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);
    }

}

If you don't care about memory usage, then it would certainly be easier to read the entire file and parse it as one big Json as mentioned in other answers.

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

回答by Somu

If you like to use Hymanson Databind(which Springuses by default for its HttpMessageConverters), then you may use the ObjectMapper.readTree(InputStream)API. For example,

如果您喜欢使用Hymanson DatabindSpring默认情况下为其使用HttpMessageConverters),那么您可以使用ObjectMapper.readTree(InputStream)API。例如,

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

回答by Sayed Saeed

if you have JSON file you can set it on assets folder then call it using this code

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

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

回答by stacker

This example reads all objects from a stream of objects, it is assumed that you need CustomObjects instead of a Map:

此示例从对象流中读取所有对象,假设您需要 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();

This answer was composed by using : Use Hymanson To Stream Parse an Array of Json Objectsand Convert JsonNode into Object

这个答案是由使用组成的:使用Hyman逊流解析一个 Json 对象数组并将JsonNode 转换为对象

回答by FarshidABZ

Kotlin version with Gson

带有 Gson 的 Kotlin 版本

to read the response JSON:

读取响应 JSON:

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

to parse response we can use Gson:

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

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