7
7
8
8
import com .google .gson .Gson ;
9
9
import com .google .gson .JsonElement ;
10
+ import com .google .gson .JsonObject ;
10
11
import com .google .gson .JsonParseException ;
11
12
import com .google .gson .TypeAdapter ;
12
13
import com .google .gson .TypeAdapterFactory ;
16
17
import com .google .gson .stream .JsonWriter ;
17
18
18
19
import java .io .IOException ;
19
- import java .util .HashSet ;
20
20
import java .util .LinkedHashMap ;
21
- import java .util .List ;
22
21
import java .util .Map ;
23
22
import java .util .Objects ;
24
- import java .util .Set ;
25
- import java .util .function .Function ;
23
+ import java .util .function .Predicate ;
26
24
27
25
/**
28
26
* Adapted from * Google GSON's RuntimeTypeAdapterFactory to support a field based adapter. Instead of adding a new
43
41
*/
44
42
public class FieldTypeAdapterFactory <T > implements TypeAdapterFactory {
45
43
private final Class <T > base ;
46
- private final Map <Class <?>, Set <String >> registeredTypes = new LinkedHashMap <>();
47
- private final Function <JsonElement , String > extractor ;
44
+ private final Map <Class <?>, Predicate <JsonObject >> registeredTypes = new LinkedHashMap <>();
48
45
49
- private FieldTypeAdapterFactory (Class <T > base , Function < JsonElement , String > extractor ) {
46
+ private FieldTypeAdapterFactory (Class <T > base ) {
50
47
this .base = base ;
51
- this .extractor = extractor ;
52
48
}
53
49
54
50
/**
55
51
* Creates a FieldTypeAdapterFactory of this type.
56
52
*
57
53
* @param base The base type for all types that this factory handles.
58
- * @param fieldExtractor A {@link Function} that takes a JSONElement and returns the extracted String field that
59
- * determines the type.
60
54
* @param <T> The base type.
61
55
* @return The created factory.
62
56
*/
63
- public static <T > FieldTypeAdapterFactory <T > of (Class <T > base , Function < JsonElement , String > fieldExtractor ) {
64
- return new FieldTypeAdapterFactory <>(base , fieldExtractor );
57
+ public static <T > FieldTypeAdapterFactory <T > of (Class <T > base ) {
58
+ return new FieldTypeAdapterFactory <>(base );
65
59
}
66
60
67
61
/**
68
- * Register a subtype for the factory with the values it is to support. If the list of matchingValues is not
69
- * disjoint across the subtypes, the order in which this method was called will determine which subType is matched.
62
+ * Register a subtype for the factory with the values it is to support.
70
63
*
71
64
* @param subType A subtype to handle.
72
- * @param matchingValues The matching values that will decide this class
65
+ * @param condition The {@link Predicate} that will decide this class
73
66
* @return this object for chaining.
74
67
*/
75
- public FieldTypeAdapterFactory <T > registerSubType (Class <? extends T > subType , List < String > matchingValues ) {
68
+ public FieldTypeAdapterFactory <T > registerSubType (Class <? extends T > subType , Predicate < JsonObject > condition ) {
76
69
Objects .requireNonNull (subType );
77
- Objects .requireNonNull (matchingValues );
78
- registeredTypes .put (subType , new HashSet <>( matchingValues ) );
70
+ Objects .requireNonNull (condition );
71
+ registeredTypes .put (subType , condition );
79
72
return this ;
80
73
}
81
74
@@ -88,26 +81,22 @@ public <R> TypeAdapter<R> create(Gson gson, TypeToken<R> type) {
88
81
for (Class <?> clazz : registeredTypes .keySet ()) {
89
82
registeredAdapters .put (clazz , gson .getAdapter (clazz ));
90
83
}
91
- return new FieldTypeAdapter <>(extractor , registeredAdapters , registeredTypes );
84
+ return new FieldTypeAdapter <>(registeredAdapters , registeredTypes );
92
85
}
93
86
94
87
// Type checking for R's super type has already happened at registration. It's safe to ignore type check warnings.
95
88
@ SuppressWarnings ("unchecked" )
96
89
private static class FieldTypeAdapter <R > extends TypeAdapter <R > {
97
- private final Function <JsonElement , String > extractor ;
98
90
private Map <Class <?>, TypeAdapter <?>> adapters ;
99
- private Map <Class <?>, Set < String >> types ;
91
+ private Map <Class <?>, Predicate < JsonObject >> types ;
100
92
101
93
/**
102
94
* Constructor for the adapter that takes an extraction mechanism and map of adapters and types.
103
95
*
104
- * @param extractor A {@link Function} that takes a {@link JsonElement} and returns the string field from it.
105
96
* @param adapters A Map of Class to TypeAdapters for that Class.
106
97
* @param types A Map of Class to the Set of Strings that are to be matched against the output of extractor.
107
98
*/
108
- public FieldTypeAdapter (Function <JsonElement , String > extractor , Map <Class <?>, TypeAdapter <?>> adapters ,
109
- Map <Class <?>, Set <String >> types ) {
110
- this .extractor = extractor ;
99
+ public FieldTypeAdapter (Map <Class <?>, TypeAdapter <?>> adapters , Map <Class <?>, Predicate <JsonObject >> types ) {
111
100
this .adapters = adapters ;
112
101
this .types = types ;
113
102
}
@@ -122,9 +111,8 @@ public void write(JsonWriter out, R value) throws IOException {
122
111
}
123
112
124
113
private TypeAdapter <R > getAdapterFor (JsonElement element ) {
125
- String field = extractor .apply (element );
126
- for (Map .Entry <Class <?>, Set <String >> entry : types .entrySet ()) {
127
- if (entry .getValue ().contains (field )) {
114
+ for (Map .Entry <Class <?>, Predicate <JsonObject >> entry : types .entrySet ()) {
115
+ if (entry .getValue ().test (element .getAsJsonObject ())) {
128
116
return (TypeAdapter <R >) adapters .get (entry .getKey ());
129
117
}
130
118
}
0 commit comments