gpt4 book ai didi

java - 如何使用 Gson 仅从 Json 反序列化某些特定字段?

转载 作者:行者123 更新时间:2023-12-01 14:14:33 27 4
gpt4 key购买 nike

我有以下 JSON 字符串

 [
{
"channel": "/bvmt/initValues",
"data": {
"value": {
"instrumentIds": "['TN0007250012','TN0007500010']",
"instruments": "[{'mnemonic':'ADWYA','marche':'ADWYA','phaut':5.82,'open':5.82,'nbrTrans':7,'veille':5.82,'time':'11:14:28','recapChange':0.00,'state':'','variation':'.','ref':5.82,'stateGrp':'S','percentChange':-0.34,'last':5.80,'bestTransaction':[{'value':5.82,'qte':'3','time':'10:00:00'},{'value':5.82,'qte':'5','time':'10:02:26'},{'value':5.82,'qte':'145','time':'10:23:27'},{'value':5.81,'qte':'100','time':'10:23:42'},{'value':5.80,'qte':'1000','time':'10:23:42'},{'value':5.73,'qte':'1','time':'10:31:21'},{'value':5.80,'qte':'100','time':'11:14:28'}],'volume':7857.19,'id':'TN0007250012','bestLimits':[{'quantiteAchat':2600,'timeVente':'11:44:10','ordreAchat':1,'prixAchat':5.76,'quantiteVente':100,'timeAchat':'11:44:10','ordreVente':1,'prixVente':5.90},{'quantiteAchat':50,'timeVente':'11:44:10','ordreAchat':1,'prixAchat':5.74,'quantiteVente':210,'timeAchat':'11:44:10','ordreVente':1,'prixVente':5.95},{'quantiteAchat':250,'timeVente':'11:44:10','ordreAchat':2,'prixAchat':5.75,'quantiteVente':187,'timeAchat':'11:44:10','ordreVente':1,'prixVente':5.94},{'quantiteAchat':189,'timeVente':'11:44:10','ordreAchat':3,'prixAchat':5.73,'quantiteVente':1112,'timeAchat':'11:44:10','ordreVente':1,'prixVente':5.97},{'quantiteAchat':44,'timeVente':'11:44:10','ordreAchat':1,'prixAchat':5.72,'quantiteVente':400,'timeAchat':'11:44:10','ordreVente':1,'prixVente':5.98}],'openStatus':'','cto':0,'valuer':'ADWYA','pbas':5.73,'grp':'S','abrv':'ADWYA','houv':'','qto':0,'seuilBas':5.65,'vto':0,'quantite':1354,'seuilHaut':5.99},{'mnemonic':'WIFAK','marche':'WIFAK','phaut':7.11,'open':7.00,'nbrTrans':2,'veille':7.13,'time':'10:24:15','recapChange':0.00,'state':'','variation':'.','ref':7.13,'stateGrp':'S','percentChange':-0.28,'last':7.11,'bestTransaction':[{'value':7.00,'qte':'99','time':'10:17:00'},{'value':7.11,'qte':'100','time':'10:24:15'}],'volume':1404.00,'id':'TN0007200017','bestLimits':[{'quantiteAchat':100,'timeVente':'11:00:19','ordreAchat':1,'prixAchat':6.80,'quantiteVente':100,'timeAchat':'11:00:19','ordreVente':1,'prixVente':7.09},{'quantiteAchat':0,'timeVente':'11:00:19','ordreAchat':0,'prixAchat':0.00,'quantiteVente':82,'timeAchat':'11:00:19','ordreVente':1,'prixVente':7.11},{'quantiteAchat':0,'timeVente':'11:00:19','ordreAchat':0,'prixAchat':0.00,'quantiteVente':284,'timeAchat':'11:00:19','ordreVente':2,'prixVente':7.10},{'quantiteAchat':0,'timeVente':'11:00:19','ordreAchat':0,'prixAchat':0.00,'quantiteVente':222,'timeAchat':'11:00:19','ordreVente':1,'prixVente':7.12},{'quantiteAchat':0,'timeVente':'11:00:19','ordreAchat':0,'prixAchat':0.00,'quantiteVente':110,'timeAchat':'11:00:19','ordreVente':2,'prixVente':7.13}],'openStatus':'','cto':0,'valuer':'WIFACK INT BANK','pbas':7.00,'grp':'S','abrv':'WIFAK','houv':'','qto':0,'seuilBas':6.92,'vto':0,'quantite':199,'seuilHaut':7.34}]"
},
"action": "initValues",
"infoSession": {
"lastInstrumentOrder": 11672,
"state": 1,
"lastInstrumentTime": "12:03:00",
"tradingTime": "08:04:02",
"tradingDate": "2017-04-24"
}
},
"id": "5"
},
{
"channel": "/bvmt/process",
"successful": true,
"id": "5"
}
]

我只对“instruments”字段的内容感兴趣,我只想获取“mnemonic”和“percentChange”字段并将它们反序列化为这样的对象数组

public class Data 
{
public List<MyObject> objects;
}

public class MyObject
{
String mnemonic;
Float percentChange;
}

我如何使用 Gson 执行此操作?

最佳答案

实际上,您有十几种方法。这仅取决于您管理 JSON 文档的方式。让我们先声明几个 DTO:

final class Data {

final List<MyObject> objects;

Data(final List<MyObject> objects) {
this.objects = objects;
}

}
final class MyObject {

final String mnemonic;
final Float percentChange;

MyObject(final String mnemonic, final Float percentChange) {
this.mnemonic = mnemonic;
this.percentChange = percentChange;
}

}

这里有一些方法:

纯 JsonElement 树

以下示例使用 Java 8 Stream API 和 Gson JSON 树工具,这对我来说似乎是最简单的方法:

private static final Gson gson = new Gson();

static Data testUsingJsonTreesOnly(final Reader reader) {
final List<MyObject> objects = StreamSupport.stream(gson.fromJson(reader, JsonElement.class).getAsJsonArray().spliterator(), false)
.map(JsonElement::getAsJsonObject)
.map(jsonObject -> jsonObject.get("data"))
.filter(Objects::nonNull)
.map(JsonElement::getAsJsonObject)
.map(jsonObject -> jsonObject.get("value"))
.filter(Objects::nonNull)
.map(JsonElement::getAsJsonObject)
.map(jsonObject -> jsonObject.get("instruments"))
.filter(Objects::nonNull)
.map(JsonElement::getAsJsonPrimitive)
.map(JsonPrimitive::getAsString)
.map(json -> gson.fromJson(json, JsonElement.class))
.map(JsonElement::getAsJsonArray)
.flatMap(jsonArray -> StreamSupport.stream(jsonArray.spliterator(), false))
.map(jsonElement -> gson.fromJson(jsonElement, MyObject.class))
.collect(toList());
return new Data(objects);
}

二次映射

这种方法尝试分两次提取值:

  • 反序列化“外部”对象;
  • 获取内部对象字符串并在第二遍中将其反序列化。
private static final Gson gson = new Gson();

private static final Type channelViewListType = new TypeToken<List<ChannelView>>() {
}.getType();

private static final Type myObjectListType = new TypeToken<List<MyObject>>() {
}.getType();

static Data testUsingDeserializationWithStrings(final Reader reader) {
final List<MyObject> objects = gson.<List<ChannelView>>fromJson(reader, channelViewListType)
.stream()
.filter(Objects::nonNull)
.map(view -> view.data)
.filter(Objects::nonNull)
.map(view -> view.value)
.filter(Objects::nonNull)
.map(view -> view.instruments)
.map((Function<String, List<MyObject>>) instruments -> gson.fromJson(instruments, myObjectListType))
.flatMap(Collection::stream)
.collect(toList());
return new Data(objects);
}

private static final class ChannelView {

final DataView data = null;

}

private static final class DataView {

final ValueView value = null;

}

private static final class ValueView {

final String instruments = null;

}

使用类型适配器的一次性映射

我认为这是第 3 级:您可以实现特定类型的适配器来“打开”编码的 JSON 文档。 @JsonAdapter 可用于指定包含特定“内部”JSON 文档的字段:

private static final Gson gson = new Gson();

private static final Type channelViewListType = new TypeToken<List<ChannelView>>() {
}.getType();

static Data testUsingDeserializationWithJsonAdapter(final Reader reader) {
final List<MyObject> objects = gson.<List<ChannelView>>fromJson(reader, channelViewListType)
.stream()
.filter(Objects::nonNull)
.map(view -> view.data)
.filter(Objects::nonNull)
.map(view -> view.value)
.filter(Objects::nonNull)
.map(view -> view.instruments)
.flatMap(Collection::stream)
.collect(toList());
return new Data(objects);
}


private static final class ChannelView {

final DataView data = null;

}

private static final class DataView {

final ValueView value = null;

}

private static final class ValueView {

@JsonAdapter(UnpackedJsonTypeAdapterFactory.class)
final List<MyObject> instruments = null;

}

private static final class UnpackedJsonTypeAdapterFactory
implements TypeAdapterFactory {

@Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
return new UnpackedJsonTypeAdapter<>(gson.getAdapter(typeToken));
}

private static final class UnpackedJsonTypeAdapter<T>
extends TypeAdapter<T> {

private final TypeAdapter<T> typeAdapter;

private UnpackedJsonTypeAdapter(final TypeAdapter<T> typeAdapter) {
this.typeAdapter = typeAdapter;
}

@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final T value)
throws IOException {
out.value(typeAdapter.toJson(value));
}

@Override
public T read(final JsonReader in)
throws IOException {
final String json = in.nextString();
final JsonReader lenientIn = new JsonReader(new StringReader(json));
lenientIn.setLenient(true);
return typeAdapter.read(lenientIn);
}

}

}

纯流媒体

从概念上讲,这可能是最简单的方法,但实现起来并不容易,因为创建了一个从头到尾直接处理 JSON token 流的高级解析器。请注意,甚至没有引入 Gson 实例。

static Data testUsingStreaming(final Reader reader)
throws IOException {
final List<MyObject> myObjects = new ArrayList<>();
final JsonReader jsonReader = new JsonReader(reader);
jsonReader.beginArray();
while ( jsonReader.hasNext() ) {
jsonReader.beginObject();
while ( jsonReader.hasNext() ) {
switch ( jsonReader.nextName() ) {
case "data":
jsonReader.beginObject();
while ( jsonReader.hasNext() ) {
switch ( jsonReader.nextName() ) {
case "value":
jsonReader.beginObject();
while ( jsonReader.hasNext() ) {
switch ( jsonReader.nextName() ) {
case "instruments":
final String instrumentsJson = jsonReader.nextString();
parseInstruments(instrumentsJson, myObjects);
break;
default:
jsonReader.skipValue();
break;
}
}
jsonReader.endObject();
break;
default:
jsonReader.skipValue();
break;
}
}
jsonReader.endObject();
break;
default:
jsonReader.skipValue();
break;
}
}
jsonReader.endObject();
}
jsonReader.endArray();
return new Data(myObjects);
}

private static void parseInstruments(final String instrumentsJson, final Collection<MyObject> myObjects)
throws IOException {
final JsonReader jsonReader = new JsonReader(new StringReader(instrumentsJson));
jsonReader.setLenient(true);
jsonReader.beginArray();
while ( jsonReader.hasNext() ) {
String mnemonic = null;
Float percentChange = null;
jsonReader.beginObject();
while ( jsonReader.hasNext() ) {
final String name = jsonReader.nextName();
switch ( name ) {
case "mnemonic":
mnemonic = jsonReader.nextString();
break;
case "percentChange":
percentChange = (float) jsonReader.nextDouble();
break;
default:
jsonReader.skipValue();
break;
}
}
if ( mnemonic != null && percentChange != null ) {
myObjects.add(new MyObject(mnemonic, percentChange));
}
jsonReader.endObject();
}
jsonReader.endArray();
}

上述所有方法都产生相同的输出:

ADWYA: -0.34
WIFAK: -0.28

关于java - 如何使用 Gson 仅从 Json 反序列化某些特定字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43587973/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com