Javaリフレクションプロキシクラスを自動的に作成するためのツール

使用法:
jdkでtools.jarを使用する必要があり
ます。私のコンピューターパスは次のとおりです。WindowsのC:\ Program Files \ Java \ jdk1.8.0 \ lib \ tools.jar

java -cp ".;your_jdk_path\lib\tools.jar" CreateProxyClass TargetType.class > TargetTypeProxy.java

Linuxの場合:

java -cp ".:your_jdk_path\lib\tools.jar" CreateProxyClass TargetType.class > TargetTypeProxy.java

jarパッケージにした場合、MANIFEST.MFリストは次のようになります。

Manifest-Version: 1.0
Created-By: 1.8.0_151 (Oracle Corporation)
Main-Class: CreateProxyClass

実行コマンドは次のとおりです。

java -Xms512m -Xmx1024m -Xbootclasspath/a:tools.jar; -jar createproxyclass.jar TargetType.class > TargetTypeProxy.java

(参照)jarアプリケーションを実行して他のjarパッケージを参照する4つの方法http://www.iteye.com/topic/332580

ソースコードは次のとおりです。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by ganmin.he on 2018/3/15 0015.
 */

public class CreateProxyClass {
    
    
    private static final String COMMA_REGEX = "\\s*,\\s*";
    private static final String ACCESS_MODIFIERS = "public|protected|private";
    private static final String REMOVE_MODIFIERS = ACCESS_MODIFIERS + "|abstract|static|final|synchronized|native";
    private static final String METHOD_MODIFIERS = REMOVE_MODIFIERS + "|strictfp";
    private static final String MODIFIERS_REGEX = "((?:(?:" + METHOD_MODIFIERS + ")\\s+)*)"; // the last character is a space or spaces
    private static final String REMOVE_MODIFIERS_REGEX = "\\s+(" + REMOVE_MODIFIERS + ")|(" + REMOVE_MODIFIERS + ")\\s*";
    private static final String GENERIC_SINGLE_REGEX = "\\w+(?:\\s+extends\\s+[\\w.$]+(?:<.*>)?)?";
    private static final String GENERIC_DECLARE_REGEX = "<\\s*(?:" + GENERIC_SINGLE_REGEX + COMMA_REGEX + ")*" + GENERIC_SINGLE_REGEX + "\\s*>";
    private static final String RAW_TYPE_REGEX = "(?:\\w+\\.)+(\\w+)";
    private static final String RAW_GENERIC_ARRAY_TYPE_REGEX = "[\\w.$]+(?:<.*>)?(?:\\[])?";
    private static final String RETURN_TYPE_REGEX = "(" + RAW_GENERIC_ARRAY_TYPE_REGEX + ")";
    private static final String METHOD_REGEX = "(\\S+)";
    private static final String ARGS_REGEX = "(.*)";
    private static final String EXCEPTIONS_REGEX = "(.*)";

    private static final Pattern FUN_PATTERN = Pattern.compile(
            "\\s*" + MODIFIERS_REGEX + "(?:(" + GENERIC_DECLARE_REGEX + ")\\s+)?" + RETURN_TYPE_REGEX + "\\s+" + METHOD_REGEX
                    + "\\s*\\(\\s*" + ARGS_REGEX + "\\s*\\)\\s*" + "(?:throws\\s+" + EXCEPTIONS_REGEX + "\\s*)?" + ";" + "\\s*");

    private static final int MODIFIERS_GROUP = 1;
    private static final int GENERIC_DECLARE_GROUP = 2;
    private static final int RETURN_TYPE_GROUP = 3;
    private static final int METHOD_GROUP = 4;
    private static final int ARGS_GROUP = 5;
    private static final int EXCEPTIONS_GROUP = 6;

    private static final Pattern MODIFIERS_PATTERN = Pattern.compile(MODIFIERS_REGEX);
    private static final Pattern REMOVE_MODIFIERS_PATTERN = Pattern.compile(REMOVE_MODIFIERS_REGEX);
    // import xxx.yyy.Type;
    private static final Pattern RAW_TYPE_PATTERN = Pattern.compile(RAW_TYPE_REGEX);
    // no need to import java.lang.Xxx;
    private static final Pattern LANG_PATTERN = Pattern.compile("\\s*java\\.lang\\.\\w+\\s*");

    private static Matcher sMethodMatcher;
    private static Matcher sRemoveModifiersMatcher;
    private static Matcher sRawTypeMatcher;
    private static Matcher sLangMatcher;

    private static final char REPLACE_MARK = '#'; // pound

    private static Set<String> sImportsSet;
    private static boolean sHasClassGeneric;
    private static String sClassGenericDeclare;
    private static String sClassGenericType;
    private static Map<String, String> sClassGenericBoundMap;


    public static void main(String[] args) throws IOException {
        // java CreateProxyClass "D:\framework_intermediates\classes\android\telephony\TelephonyManager.class"
        // args = new String[]{"D:\\framework_intermediates\\classes\\android\\telephony\\TelephonyManager.class"};

        boolean isLinuxOS = System.getProperty("os.name").toLowerCase().contains("linux");

        if (args.length == 0) {
            if (isLinuxOS) {
                System.out.println(
                        "Usage: java -cp \".:jdk_path/lib/tools.jar\" CreateProxyClass \"path/to/TargetType.class\" > \"path/to/TargetTypeProxy.java\"");
            } else {
                System.out.println(
                        "Usage: java -cp \".;jdk_path\\lib\\tools.jar\" CreateProxyClass \"path\\to\\TargetType.class\" > \"path\\to\\TargetTypeProxy.java\"");
            }
            System.out.println();
            System.out.println("where possible options include:");
            System.out.println("  -p  -private                 include protected and private methods");
            System.out.println();
            return;
        }

        boolean includePrivate = false;
        for (String arg : args) {
            if (arg.equals("-p") || arg.equals("-private")) {
                includePrivate = true;
                break;
            }
        }

        String className = args[0];
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(new BufferedWriter(sw), true);
        if (includePrivate) {
            com.sun.tools.javap.Main.run(new String[]{
   
   "-p", className}, pw);
        } else {
            com.sun.tools.javap.Main.run(new String[]{className}, pw);
        }
        pw.close();
        //sw.write("private static native java.lang.String[] test$(int, boolean[],java.lang.String[], HashMap<Integer<String, Thread>, Map>[])"
        //        + "throws Exception, java.lang.RuntimeException;");
        //sw.write("public static <T extends Number & Comparable> T transform(T);");
        BufferedReader br = new BufferedReader(new StringReader(sw.toString()));

        if (className.endsWith(".class")) {
            className = className.substring(0, className.length() - 6);
        }

        int lastIndexOfSlash = className.lastIndexOf('/');
        int lastIndexOfBackSlash = className.lastIndexOf('\\');
        int maxIndex = Math.max(lastIndexOfSlash, lastIndexOfBackSlash);
        if (maxIndex > 0) {
            className = className.substring(maxIndex + 1);
        }

        StringBuilder importsSb = new StringBuilder();
        StringBuilder headSb = new StringBuilder();
        StringBuilder methodSb = new StringBuilder();

        sImportsSet = new TreeSet<>();
        sImportsSet.add("java.lang.reflect.InvocationTargetException");
        sImportsSet.add("java.lang.reflect.Method");

        String line = null;
        //String enclosingClass = null;

        // first line: source file
        line = br.readLine();

        /*if (line != null) {
            String sourceFile = line.substring(line.indexOf('\"') + 1, line.lastIndexOf('\"'));
            enclosingClass = sourceFile;
            if (sourceFile.contains(".")) {
                enclosingClass = sourceFile.substring(0, sourceFile.indexOf('.'));
            }
        }*/

        // second line: class define
        line = br.readLine();

        int leftAngle = line.indexOf('<');
        int extIndex = line.indexOf("extends");
        int impIndex = line.indexOf("implements");

        sHasClassGeneric = (leftAngle != -1) && (extIndex == -1 || leftAngle < extIndex) && (impIndex == -1 || leftAngle < impIndex);

        if (line != null) {
            String[] strs = line.trim().split("\\s+");
            for (String str : strs) {
                if (str.contains(className)) {
                    if (sHasClassGeneric) {
                        str = str.substring(0, str.indexOf('<'));
                    }
                    if (str.contains("$")) {
                        // java.util.Map$Entry --> import java.util.Map; import java.util.Map.Entry
                        String[] paths = str.split("\\$");
                        sImportsSet.add(paths[0]);
                        for (int i = 1; i < paths.length; i++) {
                            sImportsSet.add(paths[0] + "." + paths[i]);
                        }
                    } else {
                        sImportsSet.add(str);
                    }
                    break;
                }
            }

            if (sHasClassGeneric) {
                char[] chars = line.toCharArray();
                int leftIndex = -1;
                int rightIndex = -1;
                int balance = 0;

                for (int i = 0; i < chars.length; i++) {
                    if (chars[i] == '<') {
                        if (leftIndex == -1) {
                            leftIndex = i;
                        }
                        ++balance;
                    } else if (chars[i] == '>') {
                        if (--balance == 0) {
                            rightIndex = i;
                            break;
                        }
                    }
                }

                sClassGenericDeclare = new String(chars, leftIndex, rightIndex - leftIndex + 1);
                sClassGenericDeclare = replace$(sClassGenericDeclare);
                sClassGenericDeclare = movePackagePathToImports(sClassGenericDeclare);
                sClassGenericBoundMap = new LinkedHashMap<>();
                setGenericBound(sClassGenericBoundMap, sClassGenericDeclare.substring(1, sClassGenericDeclare.length() - 1));

                Iterator<String> it = sClassGenericBoundMap.keySet().iterator();
                StringBuilder sb = new StringBuilder("<");
                while (it.hasNext()) {
                    sb.append(it.next()).append(", ");
                }
                sb.delete(sb.length() - 2, sb.length());
                sb.append(">");

                sClassGenericType = sb.toString();
            }
        }

        String proxyName = className + "Proxy";
        className = replace$(className);

        headSb.append("public final class ").append(proxyName);
        if (sHasClassGeneric) {
            headSb.append(sClassGenericDeclare);
        }
        headSb.append(" {\n");

        headSb.append("    private static final Class<?> clazz = ").append(className).append(".class;\n");
        headSb.append("\n");

        headSb.append("    private ").append(className);
        if (sHasClassGeneric) {
            headSb.append(sClassGenericType);
        }
        headSb.append(" proxied;\n");
        headSb.append("\n");

        headSb.append("    private ").append(proxyName).append("(").append(className);
        if (sHasClassGeneric) {
            headSb.append(sClassGenericType);
        }
        headSb.append(" proxiedInstance) {\n");
        headSb.append("        proxied = proxiedInstance;\n");
        headSb.append("    }\n");
        headSb.append("\n");

        headSb.append("    public static ");
        if (sHasClassGeneric) {
            headSb.append(sClassGenericDeclare).append(" ");
        }
        headSb.append(proxyName);
        if (sHasClassGeneric) {
            headSb.append(sClassGenericType);
        }
        headSb.append(" getProxyInstance(").append(className);
        if (sHasClassGeneric) {
            headSb.append(sClassGenericType);
        }
        headSb.append(" proxiedInstance) {\n");
        //headSb.append("        if (proxiedInstance == null) {\n");
        //headSb.append("            throw new IllegalArgumentException(\"proxiedInstance must not be null\");\n");
        //headSb.append("        }\n");
        headSb.append("        return new ").append(proxyName);
        if (sHasClassGeneric) {
            headSb.append(sClassGenericType);
        }
        headSb.append("(proxiedInstance);\n");
        headSb.append("    }\n");
        headSb.append("\n");

        headSb.append("    private Object invokeProxiedMethod(String methodName, Class<?>[] classes, Object... objs) {\n");
        headSb.append("        try {\n");
        headSb.append("            Method method = clazz.getDeclaredMethod(methodName, classes);\n");
        headSb.append("            method.setAccessible(true);\n");
        headSb.append("            return method.invoke(proxied, objs);\n");
        headSb.append("        } catch (NoSuchMethodException | IllegalAccessException e) {\n");
        headSb.append("            e.printStackTrace();\n");
        headSb.append("        } catch (SecurityException | IllegalArgumentException e) {\n");
        headSb.append("            throw e;\n");
        headSb.append("        } catch (InvocationTargetException e) {\n");
        headSb.append("            Throwable t = e.getCause();\n");
        headSb.append("            if (t instanceof RuntimeException) {\n");
        headSb.append("                throw (RuntimeException) t;\n");
        headSb.append("            } else {\n");
        headSb.append("                e.printStackTrace();\n");
        headSb.append("            }\n");
        headSb.append("        }\n");
        headSb.append("        return null;\n");
        headSb.append("    }\n");
        headSb.append("\n");

        headSb.append("    private Object invokeProxiedMethod(String methodName, Object... objs) {\n");
        headSb.append("        Class<?>[] classes = new Class[objs.length];\n");
        headSb.append("        for (int i = 0; i < objs.length; i++) {\n");
        headSb.append("            classes[i] = objs[i].getClass();\n");
        headSb.append("        }\n");
        headSb.append("        return invokeProxiedMethod(methodName, classes, objs);\n");
        headSb.append("    }\n");

        while ((line = br.readLine()) != null) {
            line = line.trim();
            sMethodMatcher = FUN_PATTERN.matcher(line);

            if (sMethodMatcher.matches()) {
                /*for (int i = 1, count = sMethodMatcher.groupCount(); i <= count; i++) {
                    System.out.print(sMethodMatcher.group(i) + "        ");
                }
                System.out.println();*/


                // Modifiers
                String modifiers = sMethodMatcher.group(MODIFIERS_GROUP);
                if (modifiers != null) {
                    modifiers = modifiers.trim();
                    sRemoveModifiersMatcher = REMOVE_MODIFIERS_PATTERN.matcher(modifiers);
                    modifiers = sRemoveModifiersMatcher.replaceAll("").trim();
                    if (!modifiers.equals("")) {
                        modifiers = modifiers + " ";
                    }
                }

                // Generic declare
                String genericDeclare = sMethodMatcher.group(GENERIC_DECLARE_GROUP);
                if (genericDeclare != null) {
                    genericDeclare = genericDeclare.trim();
                    genericDeclare = replace$(genericDeclare);
                    genericDeclare = movePackagePathToImports(genericDeclare);
                }

                // Return type
                String retType = sMethodMatcher.group(RETURN_TYPE_GROUP).trim();
                retType = retType.trim();
                if (MODIFIERS_PATTERN.matcher(retType + " ").matches()) {
                    // if the retType string is a modifier string, this method is a constructor
                    continue;
                }
                retType = replace$(retType);
                retType = movePackagePathToImports(retType);

                // Method name
                String method = sMethodMatcher.group(METHOD_GROUP).trim();
                if (method.startsWith("lambda$") || method.endsWith("Lambda$")) {
                    continue;
                }

                // Argument list
                String arguments = sMethodMatcher.group(ARGS_GROUP).trim();
                arguments = replace$(arguments);
                arguments = movePackagePathToImports(arguments);
                arguments = replaceCommaWithMark(arguments);

                // Exception list
                String exceptions = sMethodMatcher.group(EXCEPTIONS_GROUP);
                boolean hasException = (exceptions != null);
                if (hasException) {
                    exceptions = exceptions.trim();
                }

                boolean hasMethodGeneric = (genericDeclare != null);
                boolean isNoRet = retType.equals("void");
                boolean hasArgs = !arguments.equals("");

                String[] argTypes = arguments.trim().split(COMMA_REGEX);
                int argCount = argTypes.length;
                String[] argParas = new String[argCount];

                StringBuilder argListSb = new StringBuilder();
                StringBuilder parListSb = new StringBuilder();
                StringBuilder classArrSb = new StringBuilder("new Class<?>[]{");
                // boolean hasVarArgs = false;

                // T extends Number & Comparable --> T is key, Number is value
                Map<String, String> methodGenericBoundMap = new LinkedHashMap<>();

                if (hasMethodGeneric) {
                    setGenericBound(methodGenericBoundMap, genericDeclare.substring(genericDeclare.indexOf('<') + 1, genericDeclare.lastIndexOf('>')));
                }

                if (hasArgs) {
                    for (int i = 0; i < argCount; i++) {
                        argTypes[i] = restoreComma(argTypes[i]);

                        argParas[i] = "arg" + i;
                        // String arg0, UncaughtExceptionHandler arg1, int arg2...
                        argListSb.append(argTypes[i]).append(" ").append(argParas[i]);
                        // String.class, UncaughtExceptionHandler.class, int.class...
                        if (argTypes[i].contains("<")) {
                            // List<String> --> List
                            argTypes[i] = argTypes[i].substring(0, argTypes[i].indexOf('<'));
                        } else if (argTypes[i].contains("...")) {
                            // hasVarArgs = true;
                            // Object... --> Object[]
                            argTypes[i] = argTypes[i].substring(0, argTypes[i].indexOf("...")) + "[]";
                        }

                        boolean processed = false;

                        if (hasMethodGeneric) {
                            if (methodGenericBoundMap.containsKey(argTypes[i])) {
                                // T.class --> Object.class
                                classArrSb.append(methodGenericBoundMap.get(argTypes[i])).append(".class");
                                processed = true;
                            } else if (argTypes[i].contains("[]")) {
                                String elementType = argTypes[i].substring(0, argTypes[i].indexOf('['));
                                if (methodGenericBoundMap.containsKey(elementType)) {
                                    // T[][].class --> Object[][].class
                                    String genericArr = argTypes[i].replace(elementType, methodGenericBoundMap.get(elementType));
                                    classArrSb.append(genericArr).append(".class");
                                    processed = true;
                                }
                            }
                        }

                        if (!processed && sHasClassGeneric) {
                            if (sClassGenericBoundMap.containsKey(argTypes[i])) {
                                // T.class --> Object.class
                                classArrSb.append(sClassGenericBoundMap.get(argTypes[i])).append(".class");
                                processed = true;
                            } else if (argTypes[i].contains("[]")) {
                                String elementType = argTypes[i].substring(0, argTypes[i].indexOf('['));
                                if (sClassGenericBoundMap.containsKey(elementType)) {
                                    // T[][].class --> Object[][].class
                                    String genericArr = argTypes[i].replace(elementType, sClassGenericBoundMap.get(elementType));
                                    classArrSb.append(genericArr).append(".class");
                                    processed = true;
                                }
                            }
                        }

                        if (!processed) {
                            // String.class, String[].class
                            classArrSb.append(argTypes[i]).append(".class");
                        }

                        /*
                         * if (hasVarArgs) { parListSb.append("(Object) "); }
                         */

                        // arg0, arg1, arg2...
                        parListSb.append(argParas[i]);

                        if (i < argCount - 1) {
                            argListSb.append(", ");
                            classArrSb.append(", ");
                            parListSb.append(", ");
                        }
                    }
                }

                classArrSb.append("}");

                String argList = argListSb.toString();
                String clazzArr = classArrSb.toString();
                String parList = parListSb.toString();

                if (!hasException) {
                    methodSb.append("    public ").append(modifiers);

                    if (hasMethodGeneric) {
                        methodSb.append(genericDeclare).append(" ");
                    }

                    methodSb.append(retType).append(" ").append(method).append("(").append(argList).append(") {\n");
                    methodSb.append(isNoRet ? "        " : ("        return (" + retType + ") ")).append("invokeProxiedMethod(\"").append(method).append("\"");

                    if (hasArgs) {
                        methodSb.append(", ").append(clazzArr).append(", ").append(parList);
                    }

                    methodSb.append(");\n");
                    methodSb.append("    }\n\n");
                } else {
                    exceptions = replace$(exceptions);
                    exceptions = movePackagePathToImports(exceptions);

                    List<String> list = new LinkedList<>(Arrays.asList(exceptions.trim().split(COMMA_REGEX)));
                    ListIterator<String> listIter = list.listIterator();

                    boolean containsThrowable = false;
                    boolean containsException = false;

                    StringBuilder excListSb = new StringBuilder();

                    while (listIter.hasNext()) {
                        String tmp = listIter.next();

                        switch (tmp) {
                            case "Throwable":
                                containsThrowable = true;
                                listIter.remove();
                                break;
                            case "Exception":
                                containsException = true;
                                listIter.remove();
                                break;
                            case "RuntimeException":
                                listIter.remove();
                                break;
                        }

                        // NullPointerException, InterruptedException...
                        excListSb.append(tmp).append(", ");
                    }

                    String excList = excListSb.substring(0, excListSb.length() - 2);
                    StringBuilder methodExcSb = new StringBuilder();

                    methodExcSb.append("    public ").append(modifiers);

                    if (hasMethodGeneric) {
                        methodExcSb.append(genericDeclare).append(" ");
                    }

                    methodExcSb.append(retType).append(" ").append(method).append("(").append(argList).append(") throws ").append(excList).append(" {\n");

                    methodExcSb.append("        try {\n");

                    methodExcSb.append("            Method method = clazz.getDeclaredMethod(\"").append(method).append("\"");
                    if (hasArgs) {
                        methodExcSb.append(", ").append(clazzArr);
                    }
                    methodExcSb.append(");\n");
                    methodExcSb.append("            method.setAccessible(true);\n");

                    methodExcSb.append("            ");
                    if (!isNoRet) {
                        methodExcSb.append("return (").append(retType).append(") ");
                    }
                    methodExcSb.append("method.invoke(proxied");
                    if (hasArgs) {
                        methodExcSb.append(", ").append(parList);
                    }
                    methodExcSb.append(");\n");

                    methodExcSb.append("        } catch (NoSuchMethodException | IllegalAccessException e) {\n");
                    methodExcSb.append("            e.printStackTrace();\n");
                    methodExcSb.append("        } catch (SecurityException | IllegalArgumentException e) {\n");
                    methodExcSb.append("            throw e;\n");
                    methodExcSb.append("        } catch (InvocationTargetException e) {\n");
                    methodExcSb.append("            Throwable t = e.getCause();\n");

                    int size = list.size();

                    for (int i = 0; i < size; i++) {
                        if (i == 0) {
                            methodExcSb.append("            if (t instanceof ");
                        } else {
                            methodExcSb.append("            } else if (t instanceof ");
                        }

                        String tmp = list.get(i);

                        methodExcSb.append(tmp).append(") {\n");
                        methodExcSb.append("                throw (").append(tmp).append(") t;\n");
                    }

                    methodExcSb.append("            ");
                    if (size != 0) {
                        methodExcSb.append("} else ");
                    }
                    methodExcSb.append("if (t instanceof RuntimeException) {\n");
                    methodExcSb.append("                throw (RuntimeException) t;\n");

                    if (containsException) {
                        methodExcSb.append("            } else if (t instanceof Exception) {\n");
                        methodExcSb.append("                throw (Exception) t;\n");
                    }

                    if (containsThrowable) {
                        methodExcSb.append("            } else if (t instanceof Throwable) {\n");
                        methodExcSb.append("                throw (Throwable) t;\n");
                    }

                    methodExcSb.append("            } else {\n");
                    methodExcSb.append("                e.printStackTrace();\n");
                    methodExcSb.append("            }\n");
                    methodExcSb.append("        }\n");

                    boolean isBoolRet = retType.equals("boolean");
                    boolean isCharRet = retType.equals("char");
                    boolean isPrimitiveRet = retType.equals("byte") || retType.equals("short") || retType.equals("int") || retType.equals("long")
                            || retType.equals("float") || retType.equals("double");

                    if (isNoRet) {
                        //methodExcSb.append("        return;\n");
                    } else if (isBoolRet) {
                        methodExcSb.append("        return false;\n");
                    } else if (isCharRet) {
                        methodExcSb.append("        return 0;\n");
                    } else if (isPrimitiveRet) {
                        methodExcSb.append("        return -1;\n");
                    } else {
                        methodExcSb.append("        return null;\n");
                    }

                    methodExcSb.append("    }\n\n");

                    methodSb.append(methodExcSb);
                }
            }

            // methodSb.append("---------------------------------------------------");
        }

        for (String imp : sImportsSet) {
            sLangMatcher = LANG_PATTERN.matcher(imp);
            if (!sLangMatcher.matches()) {
                importsSb.append("import " + imp + ";\n");
            }
        }

        System.out.println(importsSb);
        System.out.println(headSb);
        System.out.print(methodSb);
        System.out.println("}");
    }

    private static String replace$(String input) {
        if (input.contains("$")) {
            // java.util.Map$Entry --> java.util.Map.Entry
            return input.replace('$', '.');
        } else {
            return input;
        }
    }

    private static final int RAW_TYPE_GROUP = 1;

    private static String movePackagePathToImports(String input) {
        if (input.contains(".")) {
            sRawTypeMatcher = RAW_TYPE_PATTERN.matcher(input);
            StringBuffer rawSb = new StringBuffer();
            while (sRawTypeMatcher.find()) {
                sImportsSet.add(sRawTypeMatcher.group());
                sRawTypeMatcher.appendReplacement(rawSb, sRawTypeMatcher.group(RAW_TYPE_GROUP));
            }
            sRawTypeMatcher.appendTail(rawSb);
            return rawSb.toString();
        } else {
            return input;
        }
    }

    private static void setGenericBound(Map<String, String> genericBoundMap, String input) {
        String[] genericTypesArr = input.trim().split(COMMA_REGEX);

        for (String genericType : genericTypesArr) {
            boolean hasBound = genericType.contains("extends");

            if (hasBound) {
                // T extends Number & Comparable --> Number is the bound
                String[] splitArr = genericType.split("\\s+");
                genericBoundMap.put(splitArr[0], splitArr[2]);
            } else {
                // T --> Object is the Bound
                genericBoundMap.put(genericType, "Object");
            }
        }
    }

    private static String replaceCommaWithMark(String input) {
        if (input.contains("<")) {
            int balance = 0;
            char[] chArr = input.toCharArray();

            for (int i = 0; i < chArr.length; i++) {
                if (chArr[i] == '<') {
                    ++balance;
                } else if (chArr[i] == '>') {
                    --balance;
                } else if (chArr[i] == ',') {
                    if (balance != 0) {
                        chArr[i] = REPLACE_MARK;
                    }
                }
            }

            return new String(chArr);
        } else {
            return input;
        }
    }

    private static String restoreComma(String input) {
        return input.replace(REPLACE_MARK, ',');
    }
}

おすすめ

転載: blog.csdn.net/hegan2010/article/details/79586738