private Map createCallbackIndexMap()

in xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java [213:296]


    private Map<? super Object, ? super Object> createCallbackIndexMap(final Factory source) {
        final Callback[] originalCallbacks = source.getCallbacks();
        final Callback[] reverseEngineeringCallbacks = new Callback[originalCallbacks.length];
        final Map<? super Object, ? super Object> callbackIndexMap = new HashMap<>();
        int idxNoOp = -1;
        for (int i = 0; i < originalCallbacks.length; i++) {
            final Callback callback = originalCallbacks[i];
            if (callback == null) {
                reverseEngineeringCallbacks[i] = null;
            } else if (NoOp.class.isAssignableFrom(callback.getClass())) {
                reverseEngineeringCallbacks[i] = NoOp.INSTANCE;
                idxNoOp = i;
            } else {
                reverseEngineeringCallbacks[i] = createReverseEngineeredCallbackOfProperType(callback, i,
                    callbackIndexMap);
            }
        }

        try {
            source.setCallbacks(reverseEngineeringCallbacks);
            final Set<Class<?>> interfaces = new HashSet<>();
            final Set<Method> methods = new HashSet<>();
            Class<?> type = source.getClass();
            do {
                methods.addAll(Arrays.asList(type.getDeclaredMethods()));
                methods.addAll(Arrays.asList(type.getMethods()));
                final Class<?>[] implementedInterfaces = type.getInterfaces();
                interfaces.addAll(Arrays.asList(implementedInterfaces));
                type = type.getSuperclass();
            } while (type != null);
            for (final Iterator<Class<?>> iterator = interfaces.iterator(); iterator.hasNext();) {
                type = iterator.next();
                methods.addAll(Arrays.asList(type.getDeclaredMethods()));
            }
            for (final Iterator<Method> iter = methods.iterator(); iter.hasNext();) {
                final Method method = iter.next();
                if (!method.isAccessible()) {
                    method.setAccessible(true);
                }
                if (Factory.class.isAssignableFrom(method.getDeclaringClass())
                    || (method.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) > 0) {
                    iter.remove();
                    continue;
                }
                final Class<?>[] parameterTypes = method.getParameterTypes();
                Method calledMethod = method;
                try {
                    if ((method.getModifiers() & Modifier.ABSTRACT) > 0) {
                        calledMethod = source.getClass().getMethod(method.getName(), method.getParameterTypes());
                    }
                    callbackIndexMap.put(null, method);
                    calledMethod.invoke(source, parameterTypes == null
                        ? (Object[])null
                        : createNullArguments(parameterTypes));
                } catch (final IllegalAccessException e) {
                    final ObjectAccessException exception = new ObjectAccessException("Cannot access method", e);
                    exception.add("method", calledMethod.toString());
                    throw exception;
                } catch (final InvocationTargetException e) {
                    // OK, ignore
                } catch (final NoSuchMethodException e) {
                    final ConversionException exception = new ConversionException(
                        "CGLIB enhanced proxies wit abstract nethod that has not been implemented");
                    exception.add("proxy-superclass", type.getSuperclass().getName());
                    exception.add("method", method.toString());
                    throw exception;
                }
                if (callbackIndexMap.containsKey(method)) {
                    iter.remove();
                }
            }
            if (idxNoOp >= 0) {
                final Integer idx = Integer.valueOf(idxNoOp);
                for (final Method method : methods) {
                    callbackIndexMap.put(method, idx);
                }
            }
        } finally {
            source.setCallbacks(originalCallbacks);
        }

        callbackIndexMap.remove(null);
        return callbackIndexMap;
    }