我有以下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”字段的内容感兴趣,我只想获得“助记符”和“percentChange”字段,并将它们反序列化为像这样的对象数组
public class Data
{
public List<MyObject> objects;
}
public class MyObject
{
String mnemonic;
Float percentChange;
}
如何使用Gson做到这一点?
答案 0 :(得分:4)
实际上你已经十几种这样做了。它仅取决于您管理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;
}
}
以下是一些方法:
以下示例使用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令牌流的高级解析器。请注意,不会引入偶数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