我有一个场景,我从webservice读取json。这个Json是一个包含大量数据的节点数组
我想要实现的目标:
步骤2是必需的,因为Java impl将调用另一个服务,而该服务又需要每个节点的json以进行进一步处理。
为了达到这个目的我尝试了什么:
我的问题:
staff.json:
[
{
"name": "Joe",
"age" : 35,
"position": "dev",
"salary": 10000,
"skills":[ "angular", "aws", "java"],
"Organistaion" : "Test",
"WorkType": "Full-time"
},
{
"name": "John",
"age" : 29,
"position": "dev",
"salary": 10000,
"skills":[ "python", "c#", "java"],
"Organistaion" : "Test",
"WorkType": "Full-time"
}
Staff.java:
public class Staff {
private String name;
private int age;
private String staffJson;
.......
}
StaffSandbox.java:
public class StaffSandbox {
public static void main (String s[]) {
Gson gson = new Gson();
try (Reader reader = new FileReader("C:\\staff.json")) { // for sample code use file
// Step 1
List<Staff> staffs = gson.fromJson(reader, new TypeToken<List<Staff>>() {}.getType());
staffs.forEach(System.out::println);
// Step 2
String json = new String(Files.readAllBytes(Paths.get(("C:\\staff.json"))));
JsonArray jsonElement = gson.fromJson(json, JsonArray.class);
System.out.println( gson.toJson(jsonElement.get(0)).toString());
// Step 3
for (int i = 0; i < json.size(); i++) {
// Read the node Id and match with corresponding Staff object and add the json to it
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
答案 0 :(得分:0)
我使用正确的方法吗?解析Json两次好吗?有没有更好的方法来实现这一目标?
不是真的。您可以避免两次读取文件+在 第二次读取中节省大量内存:您将整个文件读取为字节数组,首先转换为转换为JSON数组的字符串。对大文件测试这种方法,你可能会OutOfMemoryError
。
我并不热衷于使用JsonReader,但这会是一个更好的解决方案吗?如果是这样,如何证明?
JsonReader
以流式方式标记JSON输入,它可以在很多很多情况下帮助你。
如果我理解正确,你只需要这样的东西:
private static void zip(final Gson gson, final Reader reader, final Consumer<? super JsonObject> consumer)
throws IOException {
// The next two lines request some stuff from the given Gson instance
final TypeAdapter<JsonObject> jsonObjectTypeAdapter = gson.getAdapter(JsonObject.class);
final JsonReader jsonReader = gson.newJsonReader(reader);
// Ensure that the very first token is array begin `[`
jsonReader.beginArray();
// And read all the array elements
while ( jsonReader.hasNext() ) {
// JsonReader does not consume entire input stream and can read necessary JSON token only
final JsonObject incomingJsonObject = jsonObjectTypeAdapter.read(jsonReader);
// And this is what we generate
final JsonObject outgoingJsonObject = new JsonObject();
outgoingJsonObject.add("name", incomingJsonObject.get("name"));
outgoingJsonObject.add("age", incomingJsonObject.get("age"));
outgoingJsonObject.add("staffJson", new JsonPrimitive(incomingJsonObject.toString()));
// Once a "staff row" is ready to use, just delegate it elsewhere
consumer.accept(outgoingJsonObject);
}
jsonReader.endArray();
}
请注意,上面的示例不使用像Staff
那样的Java映射。如果需要,可以使用JsonElement
和Gson.toJsonTree()
将Gson.fromJson()
转换为Java映射,反之亦然。此外,您甚至可以将输出直接写入指定的JsonWriter
,甚至不创建outgoingJsonObject
个实例(普通的R / W管道:从输入读取==&gt;进程==&gt;写入输出)。
使用示例(请注意Reader
不能使用两次或更多次;消费者实现使用不同的策略:将每个新生成的JsonObject
直接刷新到System.out
(您可以处理非常大的这样的数据集;或者将所有这些对象收集到列表然后做你想做的任何事情(集合必须适合内存)):
try ( final Reader reader = getPackageResourceReader(Q43105667.class, "staff.json") ) {
zip(gson, reader, System.out::println);
}
try ( final Reader reader = getPackageResourceReader(Q43105667.class, "staff.json") ) {
final Collection<JsonObject> list = new ArrayList<>();
zip(gson, reader, list::add);
System.out.println(list);
}
{ “名称”: “乔”, “年龄”:35, “staffJson”: “{\” 名称\ “:\” 乔\”,\ “年龄\”:35,\ “位置\”: \ “dev的\”,\ “薪水\”:10000,\ “技能\”:[\ “角\”,\ “AWS \” \ “的java \”],\ “Organistaion \”:\“测试\ “\ ”WorkType \“:\ ”全职\“}”
{ “名”: “约翰”, “年龄”:29, “staffJson”: “{\” 名称\ “:\” 约翰\ “\ ”年龄\“:29 \ ”位置\“:\” 开发\”,\ “工资\”:10000,\ “技能\”:\ “蟒蛇\”,\ “C#\”,\ “的java \”] \ “Organistaion \”:\ “测试\”,\ “WorkType \”:\ “全职\”}“
[{ “名称”: “乔”, “年龄”:35, “staffJson”: “{\” 名称\ “:\” 乔\ “\ ”年龄\“:35,\ ”位置\“:\” dev的\”,\ “薪水\”:10000,\ “技能\”:[\ “角\”,\ “AWS \” \ “的java \”],\ “Organistaion \”:\ “测试\”, \“WorkType \”:\“Full-time \”}“},{”name“:”John“,”age“:29,”staffJson“:”{\“name \”:\“John \”, \ “年龄\”:29 \ “位置\”:\ “开发\”,\ “工资\”:10000,\ “技能\”:\ “蟒蛇\”,\ “C#\”,\“的java \“],\”Organistaion \“:\”Test \“,\”WorkType \“:\”全职\“}”}}