-
Notifications
You must be signed in to change notification settings - Fork 94
/
MapDeserializer.java
116 lines (100 loc) · 4.29 KB
/
MapDeserializer.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*
* Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
package org.eclipse.yasson.internal.serializer;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.NavigableMap;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;
import jakarta.json.bind.serializer.JsonbDeserializer;
import jakarta.json.stream.JsonParser;
import org.eclipse.yasson.internal.JsonbParser;
import org.eclipse.yasson.internal.JsonbRiParser;
import org.eclipse.yasson.internal.ReflectionUtils;
import org.eclipse.yasson.internal.Unmarshaller;
/**
* Item implementation for {@link java.util.Map} fields.
* According to JSON specification object can have only string keys, given that maps could only be parsed
* from JSON objects, implementation is bound to String type.
*
* @param <T> map type
*/
public class MapDeserializer<T extends Map<?, ?>> extends AbstractContainerDeserializer<T> implements EmbeddedItem {
/**
* Type of value in the map. (Keys must always be Strings, because of JSON spec)
*/
private final Type mapValueRuntimeType;
private final T instance;
/**
* Create instance of current item with its builder.
*
* @param builder {@link DeserializerBuilder} used to build this instance
*/
protected MapDeserializer(DeserializerBuilder builder) {
super(builder);
mapValueRuntimeType = getRuntimeType() instanceof ParameterizedType
? ReflectionUtils.resolveType(this, ((ParameterizedType) getRuntimeType()).getActualTypeArguments()[1])
: Object.class;
this.instance = createInstance(builder);
}
@SuppressWarnings("unchecked")
private T createInstance(DeserializerBuilder builder) {
Class<?> rawType = ReflectionUtils.getRawType(getRuntimeType());
return rawType.isInterface()
? (T) getMapImpl(rawType, builder)
: (T) builder.getJsonbContext().getInstanceCreator().createInstance(rawType);
}
private Map getMapImpl(Class ifcType, DeserializerBuilder builder) {
if (ConcurrentMap.class.isAssignableFrom(ifcType)) {
if (SortedMap.class.isAssignableFrom(ifcType) || NavigableMap.class.isAssignableFrom(ifcType)) {
return new ConcurrentSkipListMap<>();
} else {
return new ConcurrentHashMap<>();
}
}
// SortedMap, NavigableMap
if (SortedMap.class.isAssignableFrom(ifcType)) {
Class<?> defaultMapImplType = builder.getJsonbContext().getConfigProperties().getDefaultMapImplType();
return SortedMap.class.isAssignableFrom(defaultMapImplType)
? (Map) builder.getJsonbContext().getInstanceCreator().createInstance(defaultMapImplType)
: new TreeMap<>();
}
return new HashMap<>();
}
@Override
public T getInstance(Unmarshaller unmarshaller) {
return instance;
}
@Override
public void appendResult(Object result) {
appendCaptor(getParserContext().getLastKeyName(), convertNullToOptionalEmpty(mapValueRuntimeType, result));
}
@SuppressWarnings("unchecked")
private <V> void appendCaptor(String key, V value) {
((Map<String, V>) getInstance(null)).put(key, value);
}
@Override
protected void deserializeNext(JsonParser parser, Unmarshaller context) {
final JsonbDeserializer<?> deserializer = newCollectionOrMapItem(mapValueRuntimeType, context.getJsonbContext());
appendResult(deserializer.deserialize(parser, context, mapValueRuntimeType));
}
@Override
protected JsonbRiParser.LevelContext moveToFirst(JsonbParser parser) {
parser.moveTo(JsonParser.Event.START_OBJECT);
return parser.getCurrentLevel();
}
}