Джексон JSON + дженерики Java

Я пытаюсь десериализовать/сопоставить приведенный ниже JSON с List<Bill> java-объектом, используя Jackson json library. (этот json был сгенерирован Джексоном, я опускаю эту часть для краткости)

{"bills":[{"amount":"13","billId":"billid3"}]}

Вот мой метод преобразования:

private static void convert(){
   String jsonBill =  "{\"bills\":[{\"amount\":\"13\",\"billId\":\"billid3\"}]}";

   ObjectMapper mapper = new ObjectMapper();
   List<Bill> bills = null;
   try {
       bills = mapper.readValue(jsonBill, new TypeReference<List<Bill>>() { });
   } catch (Exception e) {
       e.printStackTrace();
   }
   System.out.println("bills = " + bills.size());
}

Сущность Билла ниже:

@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS)
public class Bill { 
   private String amount;
   private String billId;

   public String getBillId() {
       return billId;
   }
   public void setBillId(String billId) {
       this.billId = billId;
   }
   public String getAmount() {
       return amount;
   }
   public void setAmount(String amount) {
       this.amount = amount;
   } 
}

и я получаю эту ошибку:

**org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.util.List out of START_OBJECT token
 at [Source: java.io.StringReader@7a84e4; line: 1, column: 1]**
 at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:160)
 at org.codehaus.jackson.map.deser.StdDeserializationContext.mappingException(StdDeserializationContext.java:194)
 at org.codehaus.jackson.map.deser.CollectionDeserializer.deserialize(CollectionDeserializer.java:103)
 at org.codehaus.jackson.map.deser.CollectionDeserializer.deserialize(CollectionDeserializer.java:93)
 at org.codehaus.jackson.map.deser.CollectionDeserializer.deserialize(CollectionDeserializer.java:25)
 at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:1980)
 at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1278)

Вот мой упрощенный контроллер Spring3, который возвращает i/p json (с сопоставлением Джексона, настроенным как представление по умолчанию):

@ModelAttribute("bills")
@RequestMapping(value = "/", method = RequestMethod.GET)
public List<Bill> fetchBills() throws IOException {
    Bill bill = new Bill();
    bill.setAmount("13");
    bill.setBillId("billid3");

    List<Bill> bills = new ArrayList<Bill>();
    bills.add(bill);
    return bills;
}

Думаю, я упускаю что-то очевидное... но не уверен, что это такое... Есть идеи?


person Ravi    schedule 15.12.2010    source источник
comment
Вы не говорите ему сопоставить атрибут «счета» со списком billLst. Я никогда не делал этого напрямую (Spring 3.0 делает это автоматически), но я ожидал увидеть ссылку на атрибут «счета».   -  person sioked    schedule 15.12.2010
comment
Да, это была опечатка с моей стороны - обновил свой пост. Спасибо. Но проблема все равно есть..   -  person Ravi    schedule 15.12.2010


Ответы (2)


Проблема заключается не в вашем коде, а в вашем примере ввода. То, что вы на самом деле пытаетесь десериализовать, — это объект с полем с именем «счета», а не список! Что вы должны использовать в качестве входных данных:

[{"billId":"billid3","amount":"13"}]

Это массив объектов, который преобразуется в список.

person Jason Nichols    schedule 15.12.2010
comment
ааа .. Спасибо за указатель. Я использую spring3 + Jackson Mapper, и контроллер json i/p, который я использовал, был возвращен. - person Ravi; 15.12.2010
comment
Поэтому мне нужно преобразовать {bills:[{amount:13,billId:billid3}]} в [{billId:billid3,amount:13}] на стороне клиента. Я ищу метод оболочки Джексона, который позволяет мне делать это без какого-либо специального кода. - person Ravi; 15.12.2010
comment
Ах, у меня нет опыта работы со Spring+Jackson, поэтому я не могу дать больше информации. Желаем удачи! - person Jason Nichols; 15.12.2010
comment
Обертка должна быть тривиальной: просто создайте простой POJO, например: public class Wrapper { List‹Bill› bills; } и передайте 'Wrapper.class' как тип для метода readValue()/ - person StaxMan; 15.12.2010
comment
Я хотел избежать написания какого-либо пользовательского кода (например, фиктивной оболочки), если это возможно. Но я пока поживу. Спасибо Стаксман. - person Ravi; 16.12.2010
comment
Этот компонент-оболочка является частью вашей объектной модели: модель должна соответствовать структуре JSON, поэтому, если вы хотите обернуть свои счета в счета, это необходимо. Но действительно ли вам нужна эта часть «счета: [...]» в любом случае? Почему бы просто не обработать обычный список и забыть о фиктивных свойствах и обертках? Нет необходимости добавлять такой дополнительный уровень, если вам нужен только список. - person StaxMan; 16.12.2010
comment
так что это реальный ответ, жесткий! :D хороший... @Jason Nichols - person gumuruh; 10.04.2012

Попробуйте использовать ObjectWriter вместо ObjectMapper

Writer writer=new StringWriter();

        ObjectWriter oWriter=om.writerWithType(new TypeReference<List<Bill>>() {
        });
        oWriter.writeValue(writer, result);

Я использую джексон 1.9.2

person neoreeprast    schedule 14.12.2011