OK,所以,這個問題正確地指出的:這是不可能使用JSON的地圖,其中鍵不是字符串。因此,要在JavaScript中模擬Java Map,必須走更長的路徑,這通常會涉及將地圖轉換爲...其他東西。
我選擇什麼是陣列的很平常數組:
地圖如
{
a:b,
c:d,
}
然後將被翻譯成陣列
[
[a,b],
[c,d],
]
什麼是所需要的的相關詳細步驟以獲得該結果
配置自定義(德)序列化
這是通過一個串行出廠設置到對象映射器獲得,爲Jackson doc clearly explains:
/**
* Associates all maps with our custom serialization mechanism, which will transform them into arrays of arrays
* @see MapAsArraySerializer
* @return
*/
@Produces
public SerializerFactory createSerializerFactory() {
CustomSerializerFactory customized = new CustomSerializerFactory();
customized.addGenericMapping(Map.class, new MapAsArraySerializer());
return customized;
}
public @Produces ObjectMapper createMapper() {
ObjectMapper jsonMapper = new ObjectMapper();
// ....
// now configure serializer
jsonMapper.setSerializerFactory(createSerializerFactory());
// ....
return jsonMapper;
}
的過程似乎很簡單,主要是因爲序列化提供系列化相當正確的多態性功能,這是不是好反序列化。事實上,正如doc also states,反序列化需要增加明確的類的映射,這是不以任何面向對象的方式使用(的傳承是不支持那裏)
/**
* Defines a deserializer for each and any used map class, as there is no inheritence support ind eserialization
* @return
*/
@Produces
public DeserializerProvider createDeserializationProvider() {
// Yeah it's not even a standard Jackson class, it'll be explained why later
CustomDeserializerFactory factory = new MapAsArrayDeserializerFactory();
List<Class<? extends Map>> classesToHandle = new LinkedList<>();
classesToHandle.add(HashMap.class);
classesToHandle.add(LinkedHashMap.class);
classesToHandle.add(TreeMap.class);
for(Class<? extends Map> c : classesToHandle) {
addClassMappingFor(c, c, factory);
}
// and don't forget interfaces !
addClassMappingFor(Map.class, HashMap.class, factory);
addClassMappingFor(SortedMap.class, TreeMap.class, factory);
return new StdDeserializerProvider(factory);
}
private void addClassMappingFor(final Class<? extends Map> detected, final Class<? extends Map> created, CustomDeserializerFactory factory) {
factory.addSpecificMapping(detected, new MapAsArrayDeserializer() {
@Override
protected Map createNewMap() throws Exception {
return created.newInstance();
}
});
}
// It's the same createMapper() method that was described upper
public @Produces ObjectMapper createMapper() {
ObjectMapper jsonMapper = new ObjectMapper();
// ....
// and deserializer
jsonMapper.setDeserializerProvider(createDeserializationProvider());
return jsonMapper;
}
現在我們已經正確定義(德)序列化是如何定製,還是我們有?實際上,沒有:MapAsArrayDeserializerFactory
值得自己解釋。
經過一番調試,我發現DeserializerProvider
代表DeserializerFactory
當沒有解串器存在類,這是很酷。但是,DeserializerFactory
根據obejct的「種類」創建解串器:如果它是一個集合,則將使用CollectionDeserializer(將該數組讀取到Collection中)。如果它是一個Map,那麼將使用MapDeserializer。
不幸的是,此解決方案使用JSON流中給出的java類(特別是在使用polymorphic deserialization時,這是我的情況)。因此,配置自定義序列化沒有影響,除非CustomDeserializerFactory
定製......這樣的:
public class MapAsArrayDeserializerFactory extends CustomDeserializerFactory {
@Override
public JsonDeserializer<?> createMapDeserializer(DeserializationConfig config, MapType type, DeserializerProvider p) throws JsonMappingException {
return createBeanDeserializer(config, type, p);
}
}
啊,我反序列化所有地圖豆。但是現在,我所有的反序列化器都被正確地調用了。
序列化
現在,序列化是一個相當簡單的任務:
public class MapAsArraySerializer extends JsonSerializer<Map> {
@SuppressWarnings("unchecked")
private Set asListOfLists(Map<?, ?> value) {
Set returned = new HashSet<>();
for(Map.Entry e : value.entrySet()) {
returned.add(Arrays.asList(e.getKey(), e.getValue()));
}
return returned;
}
@Override
public void serialize(Map value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
Collection entries = asListOfLists(value);
jgen.writeObjectField("entries", entries);
}
@Override
public void serializeWithType(Map value, JsonGenerator jgen, SerializerProvider provider, TypeSerializer typeSer) throws IOException,
JsonProcessingException {
Collection entries = asListOfLists(value);
typeSer.writeTypePrefixForObject(value, jgen);
jgen.writeObjectField("entries", entries);
typeSer.writeTypeSuffixForObject(value, jgen);
}
}
反序列化
和反序列化是不是更復雜:
public abstract class MapAsArrayDeserializer<Type extends Map> extends JsonDeserializer<Type> {
protected Type newMap(Collection c, Type returned) {
for(Object o : c) {
if (o instanceof List) {
List l = (List) o;
if(l.size()==2) {
Iterator i = l.iterator();
returned.put(i.next(), i.next());
}
}
}
return returned;
}
protected abstract Type createNewMap() throws Exception;
@Override
public Type deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
if(jp.getCurrentToken().equals(JsonToken.START_OBJECT)) {
JsonToken nameToken = jp.nextToken();
String name = jp.getCurrentName();
if(name.equals("entries")) {
jp.nextToken();
Collection entries = jp.readValueAs(Collection.class);
JsonToken endMap = jp.nextToken();
try {
return newMap(entries, createNewMap());
} catch(Exception e) {
throw new IOException("unable to create receiver map", e);
}
} else {
throw new IOException("expected \"entries\", but field name was \""+name+"\"");
}
} else {
throw new IOException("not startying an object ? Not possible");
}
}
@Override
public Type deserializeWithType(JsonParser jp, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException,
JsonProcessingException {
Object value = typeDeserializer.deserializeTypedFromObject(jp, ctxt);
return (Type) value;
}
}
好,預期類是左抽象的每個聲明的子類型創建正確的馬p實例。
現在
而現在它的工作原理上無縫Java端(造成的JavaScript必須有一個地圖,相當於對象讀取這些DATAS。
它可能無所謂這裏,但你真的應該升級到一個後來的傑克遜版本,如果你想繼續使用1.x,1.9(.13)是最新版本 - 許多bug從1.5開始已經被修復了。 – StaxMan 2014-10-08 18:50:43
@StaxMan好吧,我已經想過了,但沒有卻遇到了任何真正的傑克遜蟲,但我可能會改變主意...... – Riduidel 2014-10-09 08:29:50