Джърси (+ jackson) сериализация на полето на картата

Имам проста уеб услуга за фланелки и бих искал да консумирам/произвеждам обекти, които съдържат полета на карта, като

@XmlElement
private Map<String,String> properties;

ако този низ влезе в уеб услугата,

{ properties: { key1: val1, key2: val2 )}

полето за свойства е десериализирано като нула без грешки. един и същ JSON влиза и излиза от GSON без проблеми и в краткосрочен план реших това, като накарах джърси да консумира производствени низове и използвах GSON за сериализиране/десериализиране на JSON.

някакви идеи?


person Jeffrey Blattman    schedule 05.04.2011    source източник
comment
Чували ли сте някога за JSON? Току-що го пресъздадохте ;) Въпреки че го маркирахте като такъв ... какъв е въпросът, точно? Има редица JSON парсери за Java   -  person Brian Roach    schedule 05.04.2011
comment
Моля, не обиждайте хората. Това няма да ви стигне много далеч.   -  person Chris Salij    schedule 07.04.2011
comment
@BrianRoach Ако сте прочели правилно въпроса, Джефри е споменал термина „GSON“. Gson е Java библиотека, която може да се използва за конвертиране на Java обекти в тяхното JSON представяне. Така че въпросът тук е малко по-сложен от това да извадите JSON анализатор от търсене в Google и да го използвате.   -  person Vikram Bodicherla    schedule 09.04.2012
comment
@VikramBodicherla – Виж онова нещо там горе, на което пише Редактирано на 10 април ... може би бихте искали да обърнете внимание на подобни неща в бъдеще, преди да изпръскате. Щракването върху него ще ви покаже как изглеждаше въпросът, когато го коментирах.   -  person Brian Roach    schedule 09.04.2012
comment
@BrianRoach Съжалявам за грешката ми. Но защо си толкова нервен човече! С целия сарказъм!!   -  person Vikram Bodicherla    schedule 09.04.2012


Отговори (2)


Джърси използва JAXB за сериализиране. JAXB не може да сериализира карта, тъй като няма XML тип за Java тип карта. Освен това Map е интерфейс и JAXB не харесва интерфейси. Ако използвате JAXBJackson bridge за маршал, ще се натъкнете на проблем.

Ще трябва да създадете адаптер, както е показано по-долу, и да анотирате своето свойство Map с него

@XmlJavaTypeAdapter(MapAdapter.class)
private Map<String,String> properties;

@XmlSeeAlso({ Adapter.class, MapElement.class })
public class MapAdapter<K,V> extends XmlAdapter<Adapter<K,V>, Map<K,V>>{


  @Override
  public Adapter<K,V> marshal(Map<K,V> map) throws Exception {

    if ( map == null )
      return null;

    return new Adapter<K,V>(map);
  }


  @Override
  public Map<K,V> unmarshal(Adapter<K,V> adapter) throws Exception {
    throw new UnsupportedOperationException("Unmarshalling a list into a map is not supported");
  }

  @XmlAccessorType(XmlAccessType.FIELD)
  @XmlType(name="Adapter", namespace="MapAdapter")
  public static final class Adapter<K,V>{

    List<MapElement<K,V>> item;

    public Adapter(){}

    public Adapter(Map<K,V> map){
      item = new ArrayList<MapElement<K,V>>(map.size());
      for (Map.Entry<K, V> entry : map.entrySet()) {
        item.add(new MapElement<K,V>(entry));
      }      
    }
  }

  @XmlAccessorType(XmlAccessType.FIELD)
  @XmlType(name="MapElement", namespace="MapAdapter")
  public static final class MapElement<K,V>{

    @XmlAnyElement
    private K key;

    @XmlAnyElement
    private V value; 

    public MapElement(){};

    public MapElement(K key, V value){
      this.key = key;
      this.value = value;
    }

    public MapElement(Map.Entry<K, V> entry){
      key = entry.getKey();
      value = entry.getValue();
    }

    public K getKey() {
      return key;
    }

    public void setKey(K key) {
      this.key = key;
    }

    public V getValue() {
      return value;
    }

    public void setValue(V value) {
      this.value = value;
    }


  }

}
person post2abhi    schedule 21.07.2011
comment
Благодаря. На този етап преминах към използване на GSON, но добра информация. - person Jeffrey Blattman; 22.07.2011

Една от възможностите е да използвате анотирани класове. Така например даден потребител може да бъде представен от следните данни.

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "user")
public class User { 
    private int uid;
    public int user_id;
    public String user_name;
    public String email;
    public URI image_url;
    public List<User> friends;
    public boolean admin;

    public User() {
        ...
    }
    public User(final int userid) {
        // Find user by id
    }
}

Ако върнете потребителския обект, както в следната част от кода, тогава jaxb автоматично ще сериализира списъка като JSON списък и т.н. и т.н....

@GET
@Path("/{userid}")
@Produces("application/json", "application/xml")
    public User showUser(@PathParam("userid") final int userid) {
        return new User(userid);
}
person Chris Salij    schedule 07.04.2011
comment
благодаря, но въпросът е как правилно да се премине обект с поле за карта. jersey + jackson не иска да сериализира / десериализира това. Ще се опитам да редактирам въпроса, за да стане по-ясно. - person Jeffrey Blattman; 10.04.2011
comment
Имате предвид предаване на тип обект? Jersey+Jackson не могат да се справят с това. Трябва да определите какви стойности има в обекта. - person Chris Salij; 11.04.2011
comment
добре ... не. java обектът, който трябва да бъде сериализиран / десериализиран, просто има поле, което е карта. - person Jeffrey Blattman; 20.04.2011
comment
Сигурни ли сте, че попълвате картата със стойности? Ако няма стойности, той ще бъде сериализиран като нулев обект. - person Chris Salij; 21.04.2011
comment
картата идва като json. Замених jackson с GSON и работи добре, така че предполагам, че е валиден. Опитах се да променя формата на json по различни начини, но все още получавам нула. независимо от това, ако json е невалиден, Джаксън трябва да ми го каже. - person Jeffrey Blattman; 22.04.2011