@@ -121,19 +121,65 @@ public Collection<NamedType> collectAndResolveSubtypesByClass(MapperConfig<?> co
121
121
*/
122
122
123
123
@ Override
124
- public Collection <NamedType > collectAndResolveSubtypesByName (MapperConfig <?> config ,
124
+ public Collection <NamedType > collectAndResolveSubtypesByTypeId (MapperConfig <?> config ,
125
125
AnnotatedMember property , JavaType baseType )
126
126
{
127
- // !!! TODO: implement properly
128
- return collectAndResolveSubtypesByClass (config , property , baseType );
127
+ final AnnotationIntrospector ai = config .getAnnotationIntrospector ();
128
+ Class <?> rawBase = (baseType == null ) ? property .getRawType () : baseType .getRawClass ();
129
+
130
+ // Need to keep track of classes that have been handled already
131
+ Set <Class <?>> typesHandled = new HashSet <Class <?>>();
132
+ Map <String ,NamedType > byName = new LinkedHashMap <String ,NamedType >();
133
+
134
+ // start with lowest-precedence, which is from type hierarchy
135
+ NamedType rootType = new NamedType (rawBase , null );
136
+ AnnotatedClass ac = AnnotatedClass .constructWithoutSuperTypes (rawBase , ai , config );
137
+ _collectAndResolveByTypeId (ac , rootType , config , typesHandled , byName );
138
+
139
+ // then with definitions from property
140
+ Collection <NamedType > st = ai .findSubtypes (property );
141
+ if (st != null ) {
142
+ for (NamedType nt : st ) {
143
+ ac = AnnotatedClass .constructWithoutSuperTypes (nt .getType (), ai , config );
144
+ _collectAndResolveByTypeId (ac , nt , config , typesHandled , byName );
145
+ }
146
+ }
147
+
148
+ // and finally explicit type registrations (highest precedence)
149
+ if (_registeredSubtypes != null ) {
150
+ for (NamedType subtype : _registeredSubtypes ) {
151
+ // is it a subtype of root type?
152
+ if (rawBase .isAssignableFrom (subtype .getType ())) { // yes
153
+ AnnotatedClass curr = AnnotatedClass .constructWithoutSuperTypes (subtype .getType (), ai , config );
154
+ _collectAndResolveByTypeId (curr , subtype , config , typesHandled , byName );
155
+ }
156
+ }
157
+ }
158
+ return _combineNamedAndUnnamed (typesHandled , byName );
129
159
}
130
160
131
161
@ Override
132
- public Collection <NamedType > collectAndResolveSubtypesByName (MapperConfig <?> config ,
162
+ public Collection <NamedType > collectAndResolveSubtypesByTypeId (MapperConfig <?> config ,
133
163
AnnotatedClass type )
134
164
{
135
- // !!! TODO: implement properly
136
- return collectAndResolveSubtypesByClass (config , type );
165
+ Set <Class <?>> typesHandled = new HashSet <Class <?>>();
166
+ Map <String ,NamedType > byName = new LinkedHashMap <String ,NamedType >();
167
+
168
+ NamedType rootType = new NamedType (type .getRawType (), null );
169
+ _collectAndResolveByTypeId (type , rootType , config , typesHandled , byName );
170
+
171
+ if (_registeredSubtypes != null ) {
172
+ Class <?> rawBase = type .getRawType ();
173
+ for (NamedType subtype : _registeredSubtypes ) {
174
+ // is it a subtype of root type?
175
+ if (rawBase .isAssignableFrom (subtype .getType ())) { // yes
176
+ final AnnotationIntrospector ai = config .getAnnotationIntrospector ();
177
+ AnnotatedClass curr = AnnotatedClass .constructWithoutSuperTypes (subtype .getType (), ai , config );
178
+ _collectAndResolveByTypeId (curr , subtype , config , typesHandled , byName );
179
+ }
180
+ }
181
+ }
182
+ return _combineNamedAndUnnamed (typesHandled , byName );
137
183
}
138
184
139
185
/*
@@ -143,13 +189,15 @@ public Collection<NamedType> collectAndResolveSubtypesByName(MapperConfig<?> con
143
189
*/
144
190
145
191
@ Override
192
+ @ Deprecated
146
193
public Collection <NamedType > collectAndResolveSubtypes (AnnotatedMember property ,
147
194
MapperConfig <?> config , AnnotationIntrospector ai , JavaType baseType )
148
195
{
149
196
return collectAndResolveSubtypesByClass (config , property , baseType );
150
197
}
151
198
152
199
@ Override
200
+ @ Deprecated
153
201
public Collection <NamedType > collectAndResolveSubtypes (AnnotatedClass type ,
154
202
MapperConfig <?> config , AnnotationIntrospector ai )
155
203
{
@@ -163,7 +211,8 @@ public Collection<NamedType> collectAndResolveSubtypes(AnnotatedClass type,
163
211
*/
164
212
165
213
/**
166
- * Method called to find subtypes for a specific type (class)
214
+ * Method called to find subtypes for a specific type (class), using
215
+ * type (class) as the unique key (in case of conflicts).
167
216
*/
168
217
protected void _collectAndResolve (AnnotatedClass annotatedType , NamedType namedType ,
169
218
MapperConfig <?> config , AnnotationIntrospector ai ,
@@ -193,12 +242,60 @@ protected void _collectAndResolve(AnnotatedClass annotatedType, NamedType namedT
193
242
if (st != null && !st .isEmpty ()) {
194
243
for (NamedType subtype : st ) {
195
244
AnnotatedClass subtypeClass = AnnotatedClass .constructWithoutSuperTypes (subtype .getType (), ai , config );
196
- // One more thing: name may be either in reference, or in subtype:
197
- if (!subtype .hasName ()) {
198
- subtype = new NamedType (subtype .getType (), ai .findTypeName (subtypeClass ));
199
- }
200
245
_collectAndResolve (subtypeClass , subtype , config , ai , collectedSubtypes );
201
246
}
202
247
}
203
248
}
249
+
250
+ /**
251
+ * Method called to find subtypes for a specific type (class), using
252
+ * type id as the unique key (in case of conflicts).
253
+ */
254
+ protected void _collectAndResolveByTypeId (AnnotatedClass annotatedType , NamedType namedType ,
255
+ MapperConfig <?> config ,
256
+ Set <Class <?>> typesHandled , Map <String ,NamedType > byName )
257
+ {
258
+ final AnnotationIntrospector ai = config .getAnnotationIntrospector ();
259
+ if (!namedType .hasName ()) {
260
+ String name = ai .findTypeName (annotatedType );
261
+ if (name != null ) {
262
+ namedType = new NamedType (namedType .getType (), name );
263
+ }
264
+ }
265
+ if (namedType .hasName ()) {
266
+ byName .put (namedType .getName (), namedType );
267
+ }
268
+
269
+ // only check subtypes if this type hadn't yet been handled
270
+ if (typesHandled .add (namedType .getType ())) {
271
+ Collection <NamedType > st = ai .findSubtypes (annotatedType );
272
+ if (st != null && !st .isEmpty ()) {
273
+ for (NamedType subtype : st ) {
274
+ AnnotatedClass subtypeClass = AnnotatedClass .constructWithoutSuperTypes (subtype .getType (), ai , config );
275
+ _collectAndResolveByTypeId (subtypeClass , subtype , config , typesHandled , byName );
276
+ }
277
+ }
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Helper method used for merging explicitly named types and handled classes
283
+ * without explicit names.
284
+ */
285
+ protected Collection <NamedType > _combineNamedAndUnnamed (Set <Class <?>> typesHandled ,
286
+ Map <String ,NamedType > byName )
287
+ {
288
+ ArrayList <NamedType > result = new ArrayList <NamedType >(byName .values ());
289
+
290
+ // Ok, so... we will figure out which classes have no explicitly assigned name,
291
+ // by removing Classes from Set. And for remaining classes, add an anonymous
292
+ // marker
293
+ for (NamedType t : byName .values ()) {
294
+ typesHandled .remove (t .getType ());
295
+ }
296
+ for (Class <?> cls : typesHandled ) {
297
+ result .add (new NamedType (cls ));
298
+ }
299
+ return result ;
300
+ }
204
301
}
0 commit comments