Десериализация нераспознанных данных JSON в карту JacksonJson - PullRequest
1 голос
/ 02 января 2012

У меня есть пример класса

public class Category {
private String id ;
    private String name ;

private String description ;

private String image ;

private String thumbnail ;
 private Map<String, String> custom ;
}

У меня есть ответ от сервера в формате ниже, но, например, для целей, скажем, это в файле cat.json

{"id":"mens","name":"Mens","c__showInMenu":true,"c__enableCompare":false}

   1 ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
   2 Category cat= mapper.readValue(new File("cat.json"), Category.class);

Это прекрасно работает для идентификаторов полей, имен и т. Д. Как мне написать собственный десериализатор так, чтобы любые поля в json, начинающиеся с c_, помещались в пользовательскую карту?

Я довольноновичок в Джексоне, использую шаблон отдыха Спрингс и настроил его на использование org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.

Ответы [ 2 ]

2 голосов
/ 03 января 2012

Вы можете просто использовать @JsonAnySetter.

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import org.codehaus.jackson.annotate.JsonAnySetter;
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.ObjectMapper;

public class JacksonFoo
{
  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD, Visibility.ANY);
    Category category = mapper.readValue(new File("cat.json"), Category.class);
    System.out.println(category);
    // output:
    // Category: id=mens, name=Mens, description=null, image=null, thumbnail=null, custom={c__showInMenu=true, c__enableCompare=false}
  }
}

class Category
{
  private String id;
  private String name;
  private String description;
  private String image;
  private String thumbnail;
  private Map<String, String> custom;

  @JsonAnySetter
  void addSomething(String name, String value)
  {
    if (custom == null) custom = new HashMap();
    custom.put(name, value);
  }

  @Override
  public String toString()
  {
    return String.format("Category: id=%s, name=%s, description=%s, image=%s, thumbnail=%s, custom=%s", 
        id, name, description, image, thumbnail, custom);
  }
}
0 голосов
/ 02 января 2012

Это возможно, но единственный способ, которым я могу думать, - это далеко не "чистота и совершенство". В качестве последней меры я бы порекомендовал покопаться в документации Джексона. .

Что вы можете сделать, это создать класс с полем карты, который будет содержать все свойства сериализованного объекта,вот так:

public class CustomObject {
    private Map<String,Object> map;
}

Таким образом, Джексон мог бы анализировать такие объекты:

{ map : {"id":"mens","name":"Mens","c__showInMenu":true,"c__enableCompare":false}}

Теперь у вас все еще есть нежелательная оболочка «map», которая может испортить десериализацию.Одним из решений может быть окружение входящего содержимого JSON "{map:" и закрывающим тегом "}".

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

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

...