Получить исходный код любого класса из Java-программы - PullRequest
0 голосов
/ 12 декабря 2018

Я пытаюсь получить исходный код любого класса (если он доступен) из Java-программы для целей отладки.Допустим, у меня есть ссылка Class[_], к которой я хотел бы получить исходный код.

То, что я пытался сделать до сих пор - в Scala:

val clazz = classOf[ClassDefinedInSeparateFile]

  1. clazz.getProtectionDomain.getCodeSource.getLocation.toString + "/" + clazz.getPackage.getName.replaceAll("\\.","/") + "/" + clazz.getSimpleName + ".scala" - выглядит нормально, JAR есть и содержит файл .scala, но не может открыться с помощью Source.fromFile(...).
  2. "/" + clazz.getPackage.getName.replaceAll("\\.","/") + "/" + clazz.getSimpleName + ".scala" - выглядит нормально, но не можетоткрыть с помощью Source.fromInputStream(...)

Примечания:

  • В производственной или промежуточной среде нет IDE.
  • В наших настройках JAR-файлы содержат исходный код.java или .scala файлов, поэтому декомпилятор не требуется.(По крайней мере, для исходного кода приложения, но не для зависимостей. Если фрагмент исходного кода приложения доступен, этого достаточно - большинство исключений перехватывается на уровне приложения и актуально там.)

Спасибо.

Ответы [ 3 ]

0 голосов
/ 12 декабря 2018

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

clazz.getName.replaceAll("\\.", "/") + ".scala" - правильное предположение, , но : (1) исходный код может не совпадать с классами - может быть префикс (например, src/ или любой другой)), или он может даже находиться в другом банке, и (2) классы scala не обязательно должны находиться в файлах с одинаковым именем - вы можете иметь несколько классов в одном файле, файл может называться foo.scala, некоторые классысоздаются на лету и т. д. Кроме того, пакет не всегда является каталогом в Scala (это может быть, например, объект пакета).

Если вы знаете местоположение внутри банки (а банка находится в пути к классам), способ открыть его: clazz.getClassLoader.getResourceAsStream ... но, как я уже говорил выше, уловка заключается в том, чтобы выяснить,местонахождение.Это не легко (и не существует единого стандартного способа сделать это).

Ваш лучший выбор - использовать IDE.Я понимаю, что у вас нет его в производственной среде, но вам это не нужно.Вам нужен производственный исходный код, доступный на некоторой машине, где у вас есть IDE, и который вы можете достичь с помощью простой команды scp.

0 голосов
/ 17 декабря 2018

Если я просто поместил исходный код в ту же папку, что и класс, приведенный ниже код работал бы хорошо как для кода в classpath, так и в jars

Обратите внимание, что нет никаких оснований для добавления префикса к имени "/", но вы должны найти класс верхнего уровня.

Я прошу прощения за то, что он находится в ядре Java, но я не хотел добавлять какие-либо дополнительные зависимости и хотел быть максимально понятным.

package com.stackoverflow.q53749060;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.Arrays;
import java.util.stream.Stream;

import org.junit.Test;

import com.stackoverflow.q53749060.Answer.Result.Found;
import com.stackoverflow.q53749060.Answer.Result.NotFound;
import com.stackoverflow.q53749060.MyTopLevelClass.MyNestedClass;
import com.stackoverflow.q53749060.MyTopLevelClassInAnotherJar.MyNestedClassInAnotherJar;

@SuppressWarnings("javadoc")
public class Answer {

    static final String[] EXTENSIONS = { "java", "scala" };

    @Test
    public void test() {

        Arrays.stream(EXTENSIONS)
            .flatMap(ext -> toSource(ext, MyTopLevelClass.class, MyNestedClass.class,MyTopLevelClassInAnotherJar.class,MyNestedClassInAnotherJar.class, String.class))
            .forEach(System.out::println);

    }

    public Stream<Result> toSource(final String extension, final Class<?>... classes) {

        return Arrays.stream(classes)
            .map(clazz -> toSource(extension, clazz));
    }

    public Result toSource(final String extension, final Class<?> clazz) {

        Class<?> topLevelClass = clazz;

        while (topLevelClass.getEnclosingClass() != null) {
            topLevelClass = topLevelClass.getEnclosingClass();
        }

        final String name = topLevelClass.getName()
            .replaceAll("\\.", "/") + "." + extension;

        final Thread currentThread = Thread.currentThread();

        final ClassLoader contextClassLoader = currentThread.getContextClassLoader();

        if (contextClassLoader.getResource(name) == null) {
            return new NotFound(clazz);
        }

        final String source = toSource(name, contextClassLoader);

        return new Found(clazz, name, source);
    }

    public String toSource(final String name, final ClassLoader contextClassLoader) {

        try (final InputStream resourceInputStream = contextClassLoader.getResourceAsStream(name);
                final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {

            int length;
            byte[] data = new byte[1024];

            while ((length = resourceInputStream.read(data, 0, data.length)) != -1) {
                byteArrayOutputStream.write(data, 0, length);
            }

            byteArrayOutputStream.flush();

            byte[] byteArray = byteArrayOutputStream.toByteArray();

            return new String(byteArray);

        } catch (IOException ioe) {
            throw new UncheckedIOException("Failed to read source file: " + name, ioe);
        }
    }

    static class Result {

        final Class<?> clazz;

        Result(Class<?> clazz) {
            super();
            this.clazz = clazz;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((this.clazz == null) ? 0 : this.clazz.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            Result other = (Result) obj;
            if (this.clazz == null) {
                if (other.clazz != null) {
                    return false;
                }
            } else if (!this.clazz.equals(other.clazz)) {
                return false;
            }
            return true;
        }

        @Override
        public String toString() {
            return "Result [clazz=" + this.clazz + "]";
        }

        static class Found extends Result {

            final String source;

            final String path;

            Found(Class<?> clazz, String path, String source) {
                super(clazz);
                this.path = path;
                this.source = source;
            }

            @Override
            public int hashCode() {
                final int prime = 31;
                int result = super.hashCode();
                result = prime * result + ((this.source == null) ? 0 : this.source.hashCode());
                return result;
            }

            @Override
            public boolean equals(Object obj) {
                if (this == obj) {
                    return true;
                }
                if (!super.equals(obj)) {
                    return false;
                }
                if (getClass() != obj.getClass()) {
                    return false;
                }
                Found other = (Found) obj;
                if (this.source == null) {
                    if (other.source != null) {
                        return false;
                    }
                } else if (!this.source.equals(other.source)) {
                    return false;
                }
                return true;
            }

            @Override
            public String toString() {
                return "Found [source=" + this.source + ", clazz=" + this.clazz + "]";
            }

        }

        static class NotFound extends Result {

            NotFound(Class<?> clazz) {
                super(clazz);

            }

            @Override
            public String toString() {
                return "NotFound [clazz=" + this.clazz + "]";
            }

        }
    }
}
0 голосов
/ 12 декабря 2018

Вам нужен Java Decompiler, если вы хотите получить что-то похожее на исходный исходный код в Java.

Вы не сможете получить доступ к исходному коду (ваша исполняемая программа состоит из Байт-код Java , а не Исходный код Java).

Вот ссылка на мой любимый декомпилятор Java .

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