Как извлечь значение из объекта JSON, сопоставив ключ на карте с помощью Java 8? - PullRequest
0 голосов
/ 21 сентября 2018

Я использую Java 8 и Джексона, чтобы попытаться получить значение int из объекта json.Вот некоторый похожий код, который я использовал для проверки структуры.

HashMap<String, Object> myMap = new HashMap<String, Object>();  
myMap
        .entrySet()
        .stream()
        .forEach(x -> System.out.println(x.getKey() + " => " + x.getValue()));

и результат:

myKey1 => {"number": 1}

myKey2 =>{"number": 1}

myKey3 => {"number": 2}

Я пытаюсь использовать ключ, например myKey1, для поиска значения json, т. е. {«число»: 1} и вытащить фактическое число, которое для этого ключа равно 1.

Однако я не все знаю значения ключа, только ключ, который я хочу сопоставить.Поэтому я должен сделать это динамически.Я знаю структуру значений, и она всегда одинакова, за исключением того, что число может быть разным.

Я думаю, потому что я не знаю ключи и их порядок, плюс я использую entrySet, что вынуждает меня использовать Optional, что делает это более трудным.

Вотмой код, где я на самом деле использую ключ для получения значения json:

Optional<Object> object = myMap.entrySet().stream()
        .filter(e -> e.getKey().equals(myKey))
        .map(Map.Entry::getValue)
        .findFirst();

Однако поток возвращается назад

Необязательно [{"number": 1}]

и я не могу получить число, чтобы вернуть его из метода.На самом деле у меня нет Java-класса для объекта, поэтому я предполагаю, что именно поэтому он возвращает Optional, поскольку я получаю ошибку компиляции без него, но я не уверен.

Есть идеи, как правильно это сделать?

Ответы [ 3 ]

0 голосов
/ 21 сентября 2018

Зачем перебирать все записи на карте и выполнять линейный поиск по ключу, чтобы получить значение записи?

Просто получите значение напрямую:

Object value = myMap.get(myKey);

СейчасЧто касается числа внутри value, так как вы говорите, что у вас нет класса, представляющего значения карты, наиболее вероятно, что используемая вами библиотека JSON создает Map для каждогозначение.Итак, теперь давайте предположим, что значения на самом деле представляют собой некоторую реализацию Map:

Integer = null;

if (value != null) {
    // What's the type of the value? Maybe a Map?
    if (value instanceof Map) {
        Map<String, Object> valueAsMap = (Map<String, Object>) value;
        number = (Integer) valueAsMap.get("number");
    }
}

Я предполагаю, что числа равны Integer с, но они вполне могут быть экземплярами Long иличетные Double с или BigDecimal с.Просто убедитесь, что указан точный тип, чтобы второе приведение не завершилось неудачей.


РЕДАКТИРОВАТЬ: Для полноты, вот код, когда значения не карты, анекоторый класс, который представляет узел json.Здесь я использую JsonNode из библиотеки Джексона, но подход очень похож на другие библиотеки:

Integer = null;

if (value != null) {
    if (value instanceof JsonNode) {
        JsonNode valueAsNode = (JsonNode) value;
        number = (Integer) valueAsNode.get("number").numberValue();
    }
}
0 голосов
/ 21 сентября 2018

К сожалению, я с самого начала не очень хорошо описал свою постановку задачи, но это последний рабочий код, который я смог собрать из других ответов.

Так выглядела структура данных.Ключ со значением, представляющим собой объект JSON с ключом и целым числом, другими словами вложенный объект JSON.

Ключ: myKey1 Значение: {"number": 1}

Key: myKey2 Value: {"number": 1}

Key: myKey3 Value: {"number": 2}

Я публикую его на случай, если кто-то еще столкнется с этим использованиемдело.Возможно, это не лучший способ сделать это, но это работает.

      Object value = myMap.get(keyName);
      ObjectMapper mapper = new ObjectMapper();
      String jsonString = (String) value;
      JsonNode rootNode = mapper.readTree(jsonString);    
      JsonNode numberNode = rootNode.path("number");
      System.out.println("number: " + numberNode.intValue());

и результат:

число: 1

0 голосов
/ 21 сентября 2018

findFirst() возвращает Optional.Вам нужно позвонить .get() или .orElse() или .orElseThrow() после того, как вы позвоните findFirst().

. Затем вы можете привести Object к JsonNode и получить значение.Вот полный код: -

public static void main(String[] args) throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    HashMap<String, Object> myMap = new HashMap<String, Object>();
    myMap.put("myKey1", mapper.readTree("{\"number\":1}"));
    myMap.put("myKey2", mapper.readTree("{\"number\":1}"));
    myMap.put("myKey3", mapper.readTree("{\"number\":2}"));

    System.out.println(getNumberUsingMapKey(myMap, "myKey3"));
}

private static int getNumberUsingMapKey(Map<String, Object> map, String key) throws Exception {
    return Optional.of(map.get(key))
            .map(o -> ((JsonNode) o).get("number").asInt())
            .get(); //or use one of the following depending on your needs
//                .orElse(-1);
//                .orElseThrow(Exception::new);
}

//or use this method
private static int getNumberUsingMapKeyWithoutOptional(Map<String, Object> map, String key) throws Exception {
    Object o = map.get(key);
    return ((JsonNode) o).get("number").asInt();
}

Выход

2

...