如何使用Gson仅从Json反序列化某些特定字段? [英] how to deserialize some specific fields only from Json using Gson?

查看:171
本文介绍了如何使用Gson仅从Json反序列化某些特定字段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下JSON字符串

I have the following JSON string

 [
  {
    "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"字段并将它们反序列化为这样的对象数组

I'm interested only in the content of the "instruments" field , I want to get only the "mnemonic" and "percentChange" fields and deserialize them into an array of Objects like this

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

public class MyObject
{
    String mnemonic;
    Float percentChange;
}

如何使用Gson做到这一点?

How can I do this using Gson ?

推荐答案

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

Actually you have dozen ways of doing it. It only depends on how you manage your JSON documents. Let's declare a couple of DTOs first:

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树功能,这对我来说似乎是最简单的方法:

The following example uses Java 8 Stream API and Gson JSON trees facilities, and it appears to be the simplest way to me:

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

两次通过映射

这种方法尝试通过两次传递来提取值:

Two-pass mappings

This approach way attempts to extract the values in two passes:

  • 反序列化外部"对象;
  • 获取内部对象字符串,并在第二遍中反序列化它.
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文档的字段:

One-pass mappings using type adapters

This is, I would say, level #3: you can implement a specific type adapter to "unwrap" the encoded JSON document. @JsonAdapter can be used to specified the field that contains the specific "inner" JSON document:

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

以上所有方法均产生相同的输出:

All of the approaches above produce the same output:

ADWYA:-0.34
WIFAK:-0.28

ADWYA: -0.34
WIFAK: -0.28

这篇关于如何使用Gson仅从Json反序列化某些特定字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆