【问题标题】:How to deserialize a key-value map to a list如何将键值映射反序列化为列表
【发布时间】:2019-04-16 08:51:50
【问题描述】:

我想在我的 Spring Boot 应用程序中使用 here 描述的加密股票数据。 RESTTemplate 使用 Gson 进行反序列化。响应数据如下所示:

{
  "IOST": {
    "EUR": 0.01147,
    "USD": 0.01296
  },
  "XRP": {
    "EUR": 0.2837,
    "USD": 0.3208
  },
  ...
}

我之前已经写过一个自定义的反序列化器。问题是,这是作为一个单独的对象出现的,其中键值对作为数组插入。结果应该是以下对象的列表:

public class Symbol {
    private Long id; // not relevant during conversion
    private Date timestamp; // not relevant during conversion
    private String symbol;
    private Double eurPrice;
    private Double usdPrice;
}

知道如何做到这一点吗?

【问题讨论】:

    标签: java spring-boot gson


    【解决方案1】:

    因为来自这个API 的响应是动态的并且取决于参数,所以最好的选择是在反序列化端使用动态结构。最好的选择是Map。作为键,您可以使用StringenumCurrencyCrypto。反序列化后,您可以将Map 转换为所需的POJO 类。简单例子:

    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    import com.google.gson.reflect.TypeToken;
    import java.lang.reflect.Type;
    import java.math.BigDecimal;
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;
    
    public class GsonTest {
    
        public static void main(String[] args) {
            String json = "{\"IOST\": {"
                + "    \"EUR\": 0.01147,"
                + "    \"USD\": 0.01296"
                + "  },"
                + "  \"XRP\": {"
                + "    \"EUR\": 0.2837,"
                + "    \"USD\": 0.3208"
                + "}}";
    
            Gson gson = new GsonBuilder().create();
            Type type = new TypeToken<Map<String, Map<Currency, BigDecimal>>>() {
            }.getType();
    
            Map<String, Map<Currency, BigDecimal>> response = gson.fromJson(json, type);
    
            List<Symbol> symbols = response.entrySet()
                .stream()
                .map(e -> {
                    Symbol symbol = new Symbol();
                    symbol.setSymbol(e.getKey());
                    symbol.setEurPrice(
                        e.getValue().getOrDefault(Currency.EUR, BigDecimal.ZERO).doubleValue());
                    symbol.setUsdPrice(
                        e.getValue().getOrDefault(Currency.USD, BigDecimal.ZERO).doubleValue());
    
                    return symbol;
                }).collect(Collectors.toList());
    
            System.out.println(symbols);
        }
    
        enum Currency {
            EUR,
            USD
        }
    }
    

    以上示例打印:

    [Symbol{id=null, timestamp=null, symbol='IOST', eurPrice=0.01147, usdPrice=0.01296}, Symbol{id=null, timestamp=null, symbol='XRP', eurPrice=0.2837, usdPrice=0.3208}]
    

    如果你想直接创建ListSymbol-s 你需要实现自定义反序列化器。比如看看这个问题:Parsing JSON Array to Java List Using Gson

    【讨论】:

      【解决方案2】:

      你必须像下面这样创建一个类

      public class Symbol  {
      
          private double EUR;
          private double USD;
      
          public double getEUR() {
              return EUR;
          }
      
          public void setEUR(double EUR) {
              this.EUR = EUR;
          }
      
          public double getUSD() {
              return USD;
          }
      
          public void setUSD(double USD) {
              this.USD = USD;
          }
      }
      

      上面是模型,下面是解析

      try {
              HashMap<String, Symbol> multiMap = new HashMap<String, Symbol>();
              JSONObject mJsonObject = new JSONObject(mResponse);
              Iterator<String> iter = mJsonObject.keys();
              while (iter.hasNext()) {
                  String key = iter.next();
                  try {
                      Symbol msymbol = new Symbol();
                      msymbol.setEUR(mJsonObject.getJSONObject(key).getDouble("EUR"));
                      msymbol.setEUR(mJsonObject.getJSONObject(key).getDouble("USD"));
                      multiMap.put(key, msymbol);
      
                  } catch (JSONException e) {
                      // Something went wrong!
                  }
              }
      
      
      
          }catch (Exception e){
              e.printStackTrace();
          }
      

      【讨论】:

      • 另外,您可以在您的 Android Studio 中安装 Gson 格式插件并制作模型类。使用方便
      • 这行不通。响应是一个映射,所以 IOSTXRP 只是 OP 提供的键的示例。
      • 将它转换成一个大对象会起作用,但这并不是我想要的。 XRP 和 IOST 只是两个示例值。它们有很多,使用的不应该是硬编码的。
      • 那么请提供实际的回复
      • 那应该可以不同。完整回复:{"IOST":{"EUR":0.01147,"USD":0.01296},"XRP":{"EUR":0.2837,"USD":0.3208},"LTC":{"EUR":70.28,"USD":79.43},"BCH":{"EUR":280.85,"USD":318.41},"EOS":{"EUR":4.78,"USD":5.42},"XLM":{"EUR":0.1001,"USD":0.1148},"ADA":{"EUR":0.0727,"USD":0.08201},"TRX":{"EUR":0.02333,"USD":0.02648},"XMR":{"EUR":57.61,"USD":64.94},"NEO":{"EUR":9.54,"USD":10.82},"VET":{"EUR":0.006085,"USD":0.006877},"RVN":{"EUR":0.05091,"USD":0.05752},"WAN":{"EUR":0.3643,"USD":0.4116},"WABI":{"EUR":0.4313,"USD":0.4872},"BTT":{"EUR":0.0006747,"USD":0.0007622}}
      【解决方案3】:

      Hareshs anweser 不适合 100%,但它帮助我弄清楚了:

      var url = "...";
      var entries = new ArrayList<Symbol>();
      var timestamp = Timestamp.from(Instant.now());
      Symbol symbol;
      
      ResponseEntity<JsonObject> response = restTemplate.getForEntity(url, JsonObject.class);
      
      for (Map.Entry<String, JsonElement> entry : response.getBody().entrySet()) {
          symbol = new Symbol();
          symbol.setSymbol(entry.getKey());
          symbol.setEurPrice(entry.getValue().getAsJsonObject().get("EUR").getAsDouble());
          symbol.setUsdPrice(entry.getValue().getAsJsonObject().get("USD").getAsDouble());
          symbol.setTimestamp(timestamp);
      
          entries.add(symbol);
      }
      

      这可以解决问题。但是,如果有人找到完全在 Gson 反序列化器中执行此操作的方法,我很想听听!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-13
        • 1970-01-01
        • 2021-09-18
        • 2017-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多