【发布时间】:2011-09-24 14:36:36
【问题描述】:
我正在使用java调用返回JSON对象的url:
url = new URL("my URl");
urlInputStream = url.openConnection().getInputStream();
如何将响应转换为字符串形式并进行解析?
【问题讨论】:
-
欢迎堆栈溢出!请记住在发布问题时正确格式化您的代码。
我正在使用java调用返回JSON对象的url:
url = new URL("my URl");
urlInputStream = url.openConnection().getInputStream();
如何将响应转换为字符串形式并进行解析?
【问题讨论】:
使用jackson将json输入流转换为地图或对象http://jackson.codehaus.org/
还有一些其他有用的json库,你可以google:json java
【讨论】:
{
InputStream is = HTTPClient.get(url);
InputStreamReader reader = new InputStreamReader(is);
JSONTokener tokenizer = new JSONTokener(reader);
JSONObject jsonObject = new JSONObject(tokenizer);
}
【讨论】:
我建议你必须使用 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)
【讨论】:
new StringBuilder(2048)。无论如何,逐行阅读可能并不是最好的性能。
对于那些指出您不能像这样使用 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());
【讨论】:
所有当前的答案都假设可以将整个 JSON 拉入内存,其中 InputStream 的优点是您可以一点一点地读取输入。如果您想避免一次读取整个 Json 文件,那么我建议您使用 Jackson 库(这是我个人最喜欢的,但我相信像 Gson 这样的其他人也有类似的功能)。
使用 Jackson,您可以使用 JsonParser 一次读取一个部分。下面是我编写的代码示例,它将 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 肯定会更容易。
【讨论】:
-Xmx16M 解析一个 15MB JSON 文件,而我遇到了带有实现的 -Xmx128M 的 OOM 异常将整个 JSON 放入内存中。
如果你喜欢使用Jackson Databind(Spring 默认使用它的HttpMessageConverters),那么你可以使用ObjectMapper.readTree(InputStream) API。例如,
ObjectMapper mapper = new ObjectMapper();
JsonNode json = mapper.readTree(myInputStream);
【讨论】:
如果您有 JSON 文件,您可以将其设置在 assets 文件夹中,然后使用此代码调用它
InputStream in = mResources.getAssets().open("fragrances.json");
// where mResources object from Resources class
【讨论】:
这个例子从一个对象流中读取所有对象, 假设您需要 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 Objects和Convert JsonNode into Object组成的
【讨论】:
带有 Gson 的 Kotlin 版本
读取响应 JSON:
val response = BufferedReader(
InputStreamReader(conn.inputStream, "UTF-8")
).use { it.readText() }
我们可以使用 Gson 来解析响应:
val model = Gson().fromJson(response, YourModelClass::class.java)
【讨论】:
我建议使用javax.json.Json factory 作为简洁可能的解决方案:
JsonObject json = Json.createReader(yourInputStream).readObject();
享受吧!
【讨论】: