为什么我不能打开根节点并反序列化一个对象数组?

时间:2015-06-02 11:21:26

标签: java json jackson deserialization json-deserialization

为什么我无法通过展开根节点来反序列化对象数组?

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\":\"hello@world.com\"},{\"email\":\"john.doe@example.com\"}]}";
        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]

我想在不创建包装类的情况下完成此操作。虽然这是一个示例,但我不想仅为展开根节点创建不必要的包装类。

3 个答案:

答案 0 :(得分:7)

创建ObjectReader以明确配置根名称:

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

(顺便说一下这是Jackson 2.5,你有不同的版本吗?我有DeserializationFeature而不是DeserializationConfig.Feature)

似乎通过以这种方式使用对象阅读器,您不需要全局配置&#34;展开根值&#34;功能,也不使用@JsonRootName注释。

另请注意,您可以直接请求List<Customer>而不是通过数组 - 提供给ObjectMapper.reader的类型就像ObjectMapper.readValue的第二个参数一样

答案 1 :(得分:-1)

似乎你无法逃避包装类。 根据{{​​3}},@JsonRootName注释只允许您打开包含pojo的单个实例的json: 所以它适用于这样的字符串:"{\"customer\":{\"email\":\"hello@world.com\"}}";

答案 2 :(得分:-1)

此代码对我有用:

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\":\"hello@world.com\"},{\"email\":\"john.doe@example.com\"}]}";
    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());
    }
  }
}

首先,你需要一个整个json对象的java对象。在我的例子中,这是CustomerMapping。然后,您需要一个用于客户密钥的java对象。在我的例子中,这是内部类CustomerMapping.Customer。因为customer是一个json数组,所以需要一个CustomerMapping.Customer对象列表。此外,您不需要将json数组映射到java数组并将其转换为列表。杰克逊已经为你做了。最后,您只需指定String类型的变量电子邮件并将其打印到控制台。