Вхождения метода поиска в java-методах [duplicate]

Новые Thread и решения AsyncTask уже объяснены.

AsyncTask в идеале следует использовать для коротких операций. Обычный Thread не является предпочтительным для Android.

Посмотрите альтернативное решение, используя HandlerThread и Обработчик

HandlerThread

Handy класс для запуска нового потока, который имеет петлитель. Затем петлитель можно использовать для создания классов обработчиков. Обратите внимание, что еще нужно вызвать start().

Обработчик:

Обработчик позволяет отправлять и обрабатывать объекты Message и Runnable, связанные с MessageQueue потока , Каждый экземпляр Handler связан с одним потоком и очередью сообщений этого потока. Когда вы создаете нового обработчика, он привязан к очереди потоков / сообщений потока, который его создает - с этой точки он будет доставлять сообщения и исполняемые файлы в очередь сообщений и выполнять их по мере их выхода из сообщения

Решение:

  1. Создать HandlerThread
  2. Вызов start() на HandlerThread
  3. Создайте Handler, получив Looper из HanlerThread
  4. Вставьте код связанного с вашей сетью объекта Runnable
  5. Отправьте задание Runnable на Handler

Пример фрагмента кода, адрес NetworkOnMainThreadException

HandlerThread handlerThread = new HandlerThread("URLConnection");
handlerThread.start();
handler mainHandler = new Handler(handlerThread.getLooper());

Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Log.d("Ravi", "Before IO call");
            URL page = new URL("http://www.google.com");
            StringBuffer text = new StringBuffer();
            HttpURLConnection conn = (HttpURLConnection) page.openConnection();
            conn.connect();
            InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
            BufferedReader buff = new BufferedReader(in);
            String line;
            while ( (line =  buff.readLine()) != null) {
                text.append(line + "\n");
            }
            Log.d("Ravi", "After IO call");
            Log.d("Ravi",text.toString());

        }catch( Exception err){
            err.printStackTrace();
        }
    }
};
mainHandler.post(myRunnable);

Плюсы использования этого подхода:

  1. Создание нового Thread/AsyncTask для каждая операция сети стоит дорого. Thread/AsyncTask будет уничтожен и повторно создан для следующих сетевых операций. Но с подходами Handler и HandlerThread вы можете отправить множество сетевых операций (как выполняемых задач) в одиночный HandlerThread с помощью Handler.

30
задан Kara 19 March 2014 в 00:56
поделиться

11 ответов

Для анализа байт-кода я бы рекомендовал ASM . Учитывая список классов для анализа, может быть сделан посетитель, который находит интересующие вас методы. Одна реализация, которая анализирует классы в файле jar, ниже.

Обратите внимание, что ASM использует internalNames с '/' вместо '.' как разделитель. Укажите целевой метод как стандартное объявление без модификаторов.

Например, чтобы перечислить методы, которые могли бы вызывать System.out.println ("foo") в java runtime jar :

java -cp "classes;asm-3.1.jar;asm-commons-3.1.jar" App \
    c:/java/jdk/jre/lib/rt.jar \
    java/io/PrintStream  "void println(String)"

Редактировать : добавлены номера источников и строк: обратите внимание, что это указывает только на вызов последнего целевого метода для каждого метода вызова - оригинал q хотел узнать которые . Я оставляю это как упражнение для читателя, чтобы показать номера строк объявления вызывающего метода или номера строк каждого целевого вызова, в зависимости от того, что вы на самом деле после. :)

приводит к:

LogSupport.java:44 com/sun/activation/registries/LogSupport log (Ljava/lang/String;)V
LogSupport.java:50 com/sun/activation/registries/LogSupport log (Ljava/lang/String;Ljava/lang/Throwable;)V
...
Throwable.java:498 java/lang/Throwable printStackTraceAsCause (Ljava/io/PrintStream;[Ljava/lang/StackTraceElement;)V
--
885 methods invoke java/io/PrintStream println (Ljava/lang/String;)V

источник:

public class App {
    private String targetClass;
    private Method targetMethod;

    private AppClassVisitor cv;

    private ArrayList<Callee> callees = new ArrayList<Callee>();

    private static class Callee {
        String className;
        String methodName;
        String methodDesc;
        String source;
        int line;

        public Callee(String cName, String mName, String mDesc, String src, int ln) {
            className = cName; methodName = mName; methodDesc = mDesc; source = src; line = ln;
        }
    }

    private class AppMethodVisitor extends MethodAdapter {

        boolean callsTarget;
        int line;

        public AppMethodVisitor() { super(new EmptyVisitor()); }

        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
            if (owner.equals(targetClass)
                    && name.equals(targetMethod.getName())
                    && desc.equals(targetMethod.getDescriptor())) {
                callsTarget = true;
            }
        }

        public void visitCode() {
            callsTarget = false;
        }

        public void visitLineNumber(int line, Label start) {
            this.line = line;
        }

        public void visitEnd() {
            if (callsTarget)
                callees.add(new Callee(cv.className, cv.methodName, cv.methodDesc, 
                        cv.source, line));
        }
    }

    private class AppClassVisitor extends ClassAdapter {

        private AppMethodVisitor mv = new AppMethodVisitor();

        public String source;
        public String className;
        public String methodName;
        public String methodDesc;

        public AppClassVisitor() { super(new EmptyVisitor()); }

        public void visit(int version, int access, String name,
                          String signature, String superName, String[] interfaces) {
            className = name;
        }

        public void visitSource(String source, String debug) {
            this.source = source;
        }

        public MethodVisitor visitMethod(int access, String name, 
                                         String desc, String signature,
                                         String[] exceptions) {
            methodName = name;
            methodDesc = desc;

            return mv;
        }
    }


    public void findCallingMethodsInJar(String jarPath, String targetClass,
                                        String targetMethodDeclaration) throws Exception {

        this.targetClass = targetClass;
        this.targetMethod = Method.getMethod(targetMethodDeclaration);

        this.cv = new AppClassVisitor();

        JarFile jarFile = new JarFile(jarPath);
        Enumeration<JarEntry> entries = jarFile.entries();

        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();

            if (entry.getName().endsWith(".class")) {
                InputStream stream = new BufferedInputStream(jarFile.getInputStream(entry), 1024);
                ClassReader reader = new ClassReader(stream);

                reader.accept(cv, 0);

                stream.close();
            }
        }
    }


    public static void main( String[] args ) {
        try {
            App app = new App();

            app.findCallingMethodsInJar(args[0], args[1], args[2]);

            for (Callee c : app.callees) {
                System.out.println(c.source+":"+c.line+" "+c.className+" "+c.methodName+" "+c.methodDesc);
            }

            System.out.println("--\n"+app.callees.size()+" methods invoke "+
                    app.targetClass+" "+
                    app.targetMethod.getName()+" "+app.targetMethod.getDescriptor());
        } catch(Exception x) {
            x.printStackTrace();
        }
    }

}
40
ответ дан Chadwick 27 August 2018 в 19:06
поделиться

Да, большинство современных IDE: s позволит вам либо искать способы использования метода или переменной. Кроме того, вы можете использовать отладчик и задавать точку трассировки в записи метода, печатать трассировку стека или все, что угодно при каждом вызове метода. Наконец, вы можете использовать некоторую простую оболочку для использования только метода grep для метода, такого как

find . -name '*.java' -exec grep -H methodName {} ;

. Единственный метод, который позволит вам находить вызовы, сделанные с помощью некоторого метода отражения, однако, будет использовать отладчик .

1
ответ дан Christoffer 27 August 2018 в 19:06
поделиться

Самое близкое, что я мог найти, - это метод, описанный в этом ответе на выбранный вопрос StackOverflow. проверьте это

0
ответ дан Community 27 August 2018 в 19:06
поделиться

Вы можете сделать это с помощью чего-то в своей среде IDE, такой как «Найти использование» (это то, что вызывается в Netbeans и JDeveloper). Несколько замечаний:

  1. Если ваш метод реализует метод из интерфейса или базового класса, вы можете знать только, что ваш метод POSSIBLY вызван.
  2. Многие фреймворки Java используют Reflection для вызова вашего метода (IE Spring, Hibernate, JSF и т. д.), поэтому будьте осторожны.
  3. В том же примечании ваш метод может быть вызванными некоторой структурой, рефлексивно или нет, поэтому будьте осторожны.
-1
ответ дан GreenieMeanie 27 August 2018 в 19:06
поделиться

Не существует способа сделать это (программно) через библиотеки отражения Java - вы не можете задать java.lang.reflect.Method "какие методы вы вызываете?"

Это оставляет два других варианта, о которых я могу думать:

  1. Статический анализ исходного кода. Я уверен, что это то, что делает набор инструментов Eclipse Java - вы можете посмотреть источник Eclipse за JDT и найти, что он делает, когда вы запрашиваете Eclipse для «Найти ссылки» на метод.
  2. Bytecode анализ. Вы можете проверить байт-код для вызовов метода. Я не уверен, какие библиотеки или примеры там помогут, но я не могу себе представить, что чего-то не существует.
3
ответ дан Jared 27 August 2018 в 19:06
поделиться

В eclipse выделите имя метода, а затем Ctrl + Shift + G

3
ответ дан Niyaz 27 August 2018 в 19:06
поделиться

Аннотировать метод с помощью @Deprecated (или пометить его с помощью @deprecated), включить предупреждения об устаревании, запустить компиляцию и посмотреть, какие предупреждения запускаются.

Запуск вашего компиляционного бита может быть сделан либо вызывая внешний процесс ant или с помощью API компилятора Java 6 .

5
ответ дан Robert Munteanu 27 August 2018 в 19:06
поделиться

1) В eclipse это -> щелкните правой кнопкой мыши на методе и выберите открытую иерархию вызовов или CLT+ALT+H

2) В jdeveloper это -> щелкните правой кнопкой мыши на методе и выберите вызовы или ALT+SHIFT+H

1
ответ дан Rohan Gala 27 August 2018 в 19:06
поделиться

Я сделал небольшой пример, используя @ Chadwick's. Это тест, который оценивает, если вызовы getDatabaseEngine () создаются с помощью методов, которые реализуют @Transaction.

/**
 * Ensures that methods that call {@link DatabaseProvider#getDatabaseEngine()}
 * implement the {@link @Transaction} annotation.
 *
 * @throws Exception If something occurs while testing.
 */
@Test
public void ensure() throws Exception {
    final Method method = Method.getMethod(
            DatabaseEngine.class.getCanonicalName() + " getDatabaseEngine()");

    final ArrayList<java.lang.reflect.Method> faultyMethods = Lists.newArrayList();

    for (Path p : getAllClasses()) {
        try (InputStream stream = new BufferedInputStream(Files.newInputStream(p))) {
            ClassReader reader = new ClassReader(stream);


            reader.accept(new ClassAdapter(new EmptyVisitor()) {
                @Override
                public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {

                    return new MethodAdapter(new EmptyVisitor()) {
                        @Override
                        public void visitMethodInsn(int opcode, String owner, String nameCode, String descCode) {
                            try {
                                final Class<?> klass = Class.forName(Type.getObjectType(owner).getClassName());
                                if (DatabaseProvider.class.isAssignableFrom(klass) &&
                                        nameCode.equals(method.getName()) &&
                                        descCode.equals(method.getDescriptor())) {

                                    final java.lang.reflect.Method method = klass.getDeclaredMethod(name,
                                            getParameters(desc).toArray(new Class[]{}));

                                    for (Annotation annotation : method.getDeclaredAnnotations()) {
                                        if (annotation.annotationType().equals(Transaction.class)) {
                                            return;
                                        }
                                    }

                                    faultyMethods.add(method);

                                }
                            } catch (Exception e) {
                                Throwables.propagate(e);
                            }
                        }
                    };
                }
            }, 0);

        }
    }

    if (!faultyMethods.isEmpty()) {
        fail("\n\nThe following methods must implement @Transaction because they're calling getDatabaseEngine().\n\n" + Joiner.on("\n").join
                (faultyMethods) + "\n\n");
    }

}

/**
 * Gets all the classes from target.
 *
 * @return The list of classes.
 * @throws IOException If something occurs while collecting those classes.
 */
private List<Path> getAllClasses() throws IOException {
    final ImmutableList.Builder<Path> builder = new ImmutableList.Builder<>();
    Files.walkFileTree(Paths.get("target", "classes"), new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
            if (file.getFileName().toString().endsWith(".class")) {
                builder.add(file);
            }
            return FileVisitResult.CONTINUE;
        }
    });

    return builder.build();
}

/**
 * Gets the list of parameters given the description.
 *
 * @param desc The method description.
 * @return The list of parameters.
 * @throws Exception If something occurs getting the parameters.
 */
private List<Class<?>> getParameters(String desc) throws Exception {
    ImmutableList.Builder<Class<?>> obj = new ImmutableList.Builder<>();

    for (Type type : Type.getArgumentTypes(desc)) {
        obj.add(ClassUtils.getClass(type.getClassName()));
    }

    return obj.build();
}
0
ответ дан rpvilao 27 August 2018 в 19:06
поделиться

Изменить: исходный вопрос был отредактирован, чтобы указать, что требуется время исполнения - этот ответ был дан до этого редактирования и указывает только, как это сделать во время разработки.

Если вы используете Eclipse, вы можете править щелкните этот метод и выберите «Открыть иерархию вызовов», чтобы получить эту информацию.

Обновлено после чтения комментариев: Другие IDE также поддерживают это также (по крайней мере, Netbeans и IntelliJ do)

12
ответ дан Simon Groenewolt 27 August 2018 в 19:06
поделиться
  1. щелкните правой кнопкой мыши по методу
  2. Перейдите к ссылкам и (в зависимости от вашего требования) выберите рабочую область / проект / Иерархию.

Появляется панель, в которой отображаются все ссылки на эти функции. Eclipse FTW!

5
ответ дан Smamatti 27 August 2018 в 19:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: