package org.restler.spring.mvc;

import jdk.internal.org.objectweb.asm.ClassReader;
import org.restler.spring.mvc.asm.ParameterNameDiscoveringVisitor;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ParameterNameDiscoverer {

    public String[] getParameterNames(Method method) {
        String[] result = getParameterNamesDefault(method);

        if(result == null) {
            result = getParameterNamesFromLocalVariableTable(method);
        }

        return result;
    }

    private String[] getParameterNamesDefault(Method method) {
        Parameter[] parameters = method.getParameters();
        String[] parameterNames = new String[parameters.length];

        for(int i = 0; i < parameters.length; ++i) {
            Parameter parameter = parameters[i];
            if(!parameter.isNamePresent()) {
                return null;
            }

            parameterNames[i] = parameter.getName();
        }

        if(parameterNames.length == 0) {
            return getParameterNamesFromLocalVariableTable(method);
        }

        return parameterNames;
    }

    private String[] getParameterNamesFromLocalVariableTable(Method method) {
//        Method originalMethod = findBridgedMethod(method);
        Method originalMethod = method;
        Class<?> declaringClass = originalMethod.getDeclaringClass();

        Map<Member, String[]> map = inspectClass(declaringClass);

        if (map != null) {
            return map.get(originalMethod);
        }
        return null;
    }

//    private Method findBridgedMethod(Method bridgeMethod) {
//        if(bridgeMethod == null || !bridgeMethod.isBridge()) {
//            return bridgeMethod;
//        }
//
//        List<Method> methods = new ArrayList<>();
//
//        getAllMethods(bridgeMethod.getDeclaringClass(), methods);
//
//        List<Method> candidates = methods.stream().filter(method -> isBridgedCandidate(method, bridgeMethod)).collect(Collectors.toList());
//
//
//
//
//        return candidates.get(0);
//    }
//
//    private void getAllMethods(Class<?> clazz, List<Method> result) {
//        for(Method method : clazz.getDeclaredMethods()) {
//            result.add(method);
//        }
//
//        if(clazz.getSuperclass() != null) {
//            getAllMethods(clazz.getSuperclass(), result);
//        } else if(clazz.isInterface()) {
//            for(Class<?> interf : clazz.getInterfaces()) {
//                getAllMethods(interf, result);
//            }
//        }
//    }
//
//    private boolean isBridgedCandidate(Method candidateMethod, Method bridgeMethod) {
//        return (!candidateMethod.isBridge() && !candidateMethod.equals(bridgeMethod) &&
//                candidateMethod.getName().equals(bridgeMethod.getName()) &&
//                candidateMethod.getParameterTypes().length == bridgeMethod.getParameterTypes().length);
//    }

    private Map<Member, String[]> inspectClass(Class<?> clazz) {
        InputStream inputStream = clazz.getResourceAsStream(getClassFileName(clazz));
        if (inputStream == null) {
            return null;
        }
        try {
            ClassReader classReader = new ClassReader(inputStream);
            Map<Member, String[]> map = new ConcurrentHashMap<>(32);
            classReader.accept(new ParameterNameDiscoveringVisitor(clazz, map), 0);
            return map;
        }
        catch (IOException | IllegalArgumentException ex) {
            // ignore
        } finally {
            try {
                inputStream.close();
            }
            catch (IOException ex) {
                // ignore
            }
        }
        return null;
    }

    private String getClassFileName(Class<?> clazz) {
        String name = clazz.getName();
        return name.substring(name.lastIndexOf('.')+1) + ".class";
    }
}

@@ -73,24 +73,114 @@
 lassReader;%0A
+import org.restler.client.RestlerException;%0Aimport org.restler.spring.mvc.asm.ClassUtils;%0A
 import org.r
@@ -1440,109 +1440,8 @@
 ) %7B%0A
-//        Method originalMethod = findBridgedMethod(method);%0A        Method originalMethod = method;%0A
     
@@ -1470,25 +1470,17 @@
 Class = 
-originalM
+m
 ethod.ge
@@ -1624,1410 +1624,48 @@
 get(
-originalMethod);%0A        %7D%0A        return null;%0A    %7D%0A%0A//    private Method findBridgedMethod(Method bridgeMethod) %7B%0A//        if(bridgeMethod == null %7C%7C !bridgeMethod.isBridge()) %7B%0A//            return bridgeMethod;%0A//        %7D%0A//%0A//        List%3CMethod%3E methods = new ArrayList%3C%3E();%0A//%0A//        getAllMethods(bridgeMethod.getDeclaringClass(), methods);%0A//%0A//        List%3CMethod%3E candidates = methods.stream().filter(method -%3E isBridgedCandidate(method, bridgeMethod)).collect(Collectors.toList());%0A//%0A//%0A//%0A//%0A//        return candidates.get(0);%0A//    %7D%0A//%0A//    private void getAllMethods(Class%3C?%3E clazz, List%3CMethod%3E result) %7B%0A//        for(Method method : clazz.getDeclaredMethods()) %7B%0A//            result.add(method);%0A//        %7D%0A//%0A//        if(clazz.getSuperclass() != null) %7B%0A//            getAllMethods(clazz.getSuperclass(), result);%0A//        %7D else if(clazz.isInterface()) %7B%0A//            for(Class%3C?%3E interf : clazz.getInterfaces()) %7B%0A//                getAllMethods(interf, result);%0A//            %7D%0A//        %7D%0A//    %7D%0A//%0A//    private boolean isBridgedCandidate(Method candidateMethod, Method bridgeMethod) %7B%0A//        return (!candidateMethod.isBridge() && !candidateMethod.equals(bridgeMethod) &&%0A//                candidateMethod.getName().equals(bridgeMethod.getName()) &&%0A//                candidateMethod.getParameterTypes().length == bridgeMethod.getParameterTypes().length);%0A//
+method);%0A        %7D%0A        return null;%0A
     
@@ -1792,16 +1792,27 @@
 sStream(
+ClassUtils.
 getClass
@@ -2199,10 +2199,113 @@
 ion 
-%7C 
+e) %7B%0A            throw new RestlerException(%22Can't read class from stream.%22, e);%0A        %7D%0A        catch(
 Ille
@@ -2318,33 +2318,32 @@
 umentException e
-x
 ) %7B%0A            
@@ -2338,33 +2338,75 @@
             
-// ignore
+throw new RestlerException(%22Illegal argument.%22, e);
 %0A        %7D f
@@ -2403,16 +2403,24 @@
        %7D
+%0A       
  finally
@@ -2582,196 +2582,8 @@
   %7D%0A
-        return null;%0A    %7D%0A%0A    private String getClassFileName(Class%3C?%3E clazz) %7B%0A        String name = clazz.getName();%0A        return name.substring(name.lastIndexOf('.')+1) + %22.class%22;%0A
     

Remove unused code for more readable.