3030import java .nio .ByteBuffer ;
3131import java .nio .charset .StandardCharsets ;
3232import java .util .Arrays ;
33+ import java .util .Collection ;
34+ import java .util .HashMap ;
35+ import java .util .Iterator ;
3336import java .util .List ;
3437import java .util .Map ;
3538import java .util .stream .Collectors ;
3639
40+ import javax .annotation .Nullable ;
41+
3742import com .cinchapi .common .base .CheckedExceptions ;
3843import com .cinchapi .common .base .Verify ;
3944import com .cinchapi .common .io .ByteBuffers ;
4045import com .cinchapi .common .reflect .Reflection ;
4146import com .google .common .collect .Lists ;
42- import com .google .common .collect .Maps ;
4347import com .google .common .primitives .Ints ;
4448
4549/**
@@ -63,6 +67,19 @@ public static TransformerSerializationFactory instance() {
6367 return INSTANCE ;
6468 }
6569
70+ /**
71+ * Return a list of potential factory methods that could produced a
72+ * {@link Transformer} from the provided {@code params}.
73+ *
74+ * @param params
75+ * @return the potential factory methods
76+ */
77+ private static List <Method > getPotentialFactoryMethods (Object ... params ) {
78+ return Arrays .stream (Transformers .class .getDeclaredMethods ())
79+ .filter (method -> Reflection .isCallableWith (method , params ))
80+ .collect (Collectors .toList ());
81+ }
82+
6683 /**
6784 * Serialize the {@code object} into a {@link ByteBuffer}.
6885 *
@@ -114,8 +131,27 @@ private static <T> T getSerializedObject(ByteBuffer bytes) {
114131 * intentionally kept local to this instance of the factory.
115132 * </p>
116133 */
117- private final Map <String , Class <? extends Transformer >> lambdas = Maps
118- .newHashMap ();
134+ private final Map <String , Class <? extends Transformer >> lambdas = new HashMap <String , Class <? extends Transformer >>() {
135+
136+ private static final long serialVersionUID = -407507799832599951L ;
137+
138+ @ Override
139+ public Class <? extends Transformer > put (String key ,
140+ Class <? extends Transformer > value ) {
141+ if (Arrays .stream (Transformers .class .getDeclaredMethods ())
142+ .filter (method -> method .getName ().equals (key ))
143+ .count () == 1 ) {
144+ // Don't cache overloaded methods because the associations
145+ // between the called method name and the lambda class would get
146+ // mixed up with the method that actually produces the lambda
147+ return super .put (key , value );
148+ }
149+ else {
150+ return null ;
151+ }
152+ }
153+
154+ };
119155
120156 private TransformerSerializationFactory () {}
121157
@@ -199,26 +235,41 @@ public ByteBuffer serialize(Transformer transformer) {
199235 }
200236 // Go through each of the Transformers factories and try to
201237 // guess which method produced the #transformer
202- List <Method > candidates = Arrays
203- .stream (Transformers .class .getDeclaredMethods ())
204- .filter (method -> Reflection .isCallableWith (method ,
205- params ))
206- .collect (Collectors .toList ());
207- Method method = null ;
208- for (Method candidate : candidates ) {
209- candidate .setAccessible (true );
210- Class <? extends Transformer > clazz = lambdas
211- .get (candidate .getName ());
212- if (clazz == null ) {
213- Transformer t = (Transformer ) candidate .invoke (null ,
214- params );
215- clazz = t .getClass ();
216- lambdas .put (candidate .getName (), clazz );
217- }
218- if (clazz .equals (transformer .getClass ())) {
219- method = candidate ;
220- break ;
238+ List <Method > candidates = getPotentialFactoryMethods (params );
239+ Method method = getFactoryMethod (transformer , candidates ,
240+ params );
241+ if (method == null ) {
242+ // Handle corner case of the factories take arrays as
243+ // parameters and convert them to collections
244+ boolean retry = false ;
245+ for (int i = 0 ; i < params .length ; ++i ) {
246+ Object param = params [i ];
247+ if (param instanceof Collection ) {
248+ Class <?> type = null ;
249+ Collection <?> cparam = (Collection <?>) param ;
250+ for (Object item : cparam ) {
251+ // Get the actual type of the collection to
252+ // create the array correctly
253+ type = type == null || item .getClass () == type
254+ ? item .getClass ()
255+ : Reflection .getClosestCommonAncestor (
256+ type , item .getClass ());
257+ }
258+ Object [] array = (Object []) java .lang .reflect .Array
259+ .newInstance (type , cparam .size ());
260+ Iterator <?> it = cparam .iterator ();
261+ for (int j = 0 ; j < cparam .size (); ++j ) {
262+ array [j ] = it .next ();
263+ }
264+ params [i ] = array ;
265+ retry = true ;
266+ }
221267 }
268+ candidates = retry ? getPotentialFactoryMethods (params )
269+ : candidates ;
270+ method = retry
271+ ? getFactoryMethod (transformer , candidates , params )
272+ : method ;
222273 }
223274 Verify .that (method != null ,
224275 "Cannot serialize transformer using technique "
@@ -257,6 +308,44 @@ public ByteBuffer serialize(Transformer transformer) {
257308 return serialized ;
258309 }
259310
311+ /**
312+ * Return the factory method from amongst the {@code candidates} that
313+ * produced the {@code transformer} using the provided {@code params}
314+ *
315+ * @param transformer
316+ * @param candidates
317+ * @param params
318+ * @return the factory method for the {@link Transformer}
319+ * @throws ReflectiveOperationException
320+ */
321+ @ Nullable
322+ private Method getFactoryMethod (Transformer transformer ,
323+ List <Method > candidates , Object ... params )
324+ throws ReflectiveOperationException {
325+ Method method = null ;
326+ for (Method candidate : candidates ) {
327+ candidate .setAccessible (true );
328+ Class <? extends Transformer > clazz = lambdas
329+ .get (candidate .getName ());
330+ try {
331+ if (clazz == null ) {
332+ Transformer t = (Transformer ) candidate .invoke (null ,
333+ params );
334+ clazz = t .getClass ();
335+ lambdas .put (candidate .getName (), clazz );
336+ }
337+ if (clazz .equals (transformer .getClass ())) {
338+ method = candidate ;
339+ break ;
340+ }
341+ }
342+ catch (IllegalArgumentException e ) {
343+ continue ;
344+ }
345+ }
346+ return method ;
347+ }
348+
260349 /**
261350 * The possible serialization techniques.
262351 *
0 commit comments