Почему я не могу развернуть корневой узел и десериализовать массив объектов?

Почему я не могу десериализовать массив объектов, развернув корневой узел?

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.annotate.JsonRootName;
import org.junit.Assert;
import org.junit.Test;

public class RootNodeTest extends Assert {

    @JsonRootName("customers")
    public static class Customer {
        public String email;
    }

    @Test
    public void testUnwrapping() throws IOException {
        String json = "{\"customers\":[{\"email\":\"[email protected]\"},{\"email\":\"[email protected]\"}]}";
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
        List<Customer> customers = Arrays.asList(mapper.readValue(json, Customer[].class));
        System.out.println(customers);
    }
}

Я копался в документации Джексона, и это то, что я мог понять, но после его запуска я получаю следующую ошибку:

A org.codehaus.jackson.map.JsonMappingException has been caught, Root name 'customers' does not match expected ('Customer[]') for type [array type, component type: [simple type, class tests.RootNodeTest$Customer]] at [Source: java.io.StringReader@49921538; line: 1, column: 2]

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


person Mridang Agarwalla    schedule 02.06.2015    source источник
comment
удалите скобки массива из второго параметра, пытаясь прочитать значение, и поместите их в переменную электронной почты. Преобразователь сопоставит значение строки json с объектом типа Customer, а затем сопоставит эти электронные письма в массив.   -  person Arthur Eirich    schedule 02.06.2015
comment
@ArthurEirich Я не мог понять. Не могли бы вы привести пример?   -  person Mridang Agarwalla    schedule 02.06.2015
comment
посмотри мой ответ я понял   -  person Arthur Eirich    schedule 02.06.2015


Ответы (3)


Создайте ObjectReader для явной настройки корневого имени:

@Test
public void testUnwrapping() throws IOException {
    String json = "{\"customers\":[{\"email\":\"[email protected]\"},{\"email\":\"[email protected]\"}]}";
    ObjectReader objectReader = mapper.reader(new TypeReference<List<Customer>>() {})
                                      .withRootName("customers");
    List<Customer> customers = objectReader.readValue(json);
    assertThat(customers, contains(customer("[email protected]"), customer("[email protected]")));
}

(кстати, это с Jackson 2.5, у вас есть другая версия? У меня есть DeserializationFeature, а не DeserializationConfig.Feature)

Кажется, что, используя средство чтения объектов таким образом, вам не нужно глобально настраивать функцию «развернуть корневое значение» или использовать аннотацию @JsonRootName.

Также обратите внимание, что вы можете напрямую запрашивать List<Customer>, а не через массив — тип, заданный для ObjectMapper.reader, работает так же, как второй параметр для ObjectMapper.readValue.

person araqnid    schedule 02.06.2015
comment
Вот как раз получилось. Я использовал старый импорт codehaus. Сейчас я перешел на fasterxml. Причина, по которой я использую нотацию массива вместо ссылки на тип, поскольку абстрактные классы отображаются как непокрытые, когда я запускаю Corbertura. - person Mridang Agarwalla; 02.06.2015

кажется, вы не можете избежать класса-оболочки. в соответствии с this, аннотация @JsonRootName позволит вам развернуть json, который содержит один экземпляр вашего pojo: поэтому он будет работать для строки следующим образом: "{\"customer\":{\"email\":\"[email protected]\"}}";

person Sharon Ben Asher    schedule 02.06.2015

Этот код работал для меня:

import org.codehaus.jackson.map.ObjectMapper;
import org.junit.Assert;
import org.junit.Test;

import java.io.IOException;
import java.util.List;

public class RootNodeTest extends Assert {

public static class CustomerMapping {
    public List<Customer> customer;

    public List<Customer> getCustomer() {
        return customer;
    }

    public static class Customer {
        public String email;

        public String getEmail() {
            return email;
        }
    }

}

@Test
public void testUnwrapping() throws IOException {
    String json = "{\"customer\":[{\"email\":\"[email protected]\"},{\"email\":\"[email protected]\"}]}";
    ObjectMapper mapper = new ObjectMapper();
    CustomerMapping customerMapping = mapper.readValue(json, CustomerMapping.class);
    List<CustomerMapping.Customer> customers = customerMapping.getCustomer();
    for (CustomerMapping.Customer customer : customers) {
        System.out.println(customer.getEmail());
    }
  }
}

Прежде всего, вам нужен объект java для всего объекта json. В моем случае это CustomerMapping. Затем вам нужен объект Java для вашего ключа клиента. В моем случае это внутренний класс CustomerMapping.Customer. Поскольку клиент — это массив json, вам нужен список объектов CustomerMapping.Customer. Кроме того, вам не нужно сопоставлять массив json с массивом java и затем преобразовывать его в список. Джексон уже делает это за вас. Наконец, вы просто указываете переменную email типа String и печатаете ее на консоли.

person Arthur Eirich    schedule 02.06.2015