Извлечение исходного кода scala из jar

#scala #jar #decompiling #decompiler

#java #scala #jar #декомпилятор #scalac

Вопрос:

Итак, у меня есть файл jar, который содержит scala в качестве исходного кода, и я потерял исходный код. Есть ли способ преобразовать файлы классов в jar в функции и классы scala вместо классов Java, создаваемых компилятором?

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

Заранее благодарю вас!

Комментарии:

1. У меня такая же проблема

Ответ №1:

Вам понадобится декомпилятор, специфичный для Scala. Нет причин, по которым его нельзя было бы написать, но это потребовало бы больших усилий, и, насколько я знаю, никто на самом деле этого не сделал. Конечно, это не привело бы к созданию точно исходного кода, так же как декомпиляторы для других языков этого не делают.

Комментарии:

1. Это все еще актуально в 2018 году?

2. @kaqqao Да, насколько я знаю. (За исключением того, что написание декомпилятора теперь было бы более сложным, по крайней мере, если бы вы хотели поддерживать как Scala 2.12, так и предыдущие версии.)

Ответ №2:

Scala компилируется в байт-код JVM, который является той же целью компиляции, что и Java. Если декомпилятор явно не нацелен на Scala, декомпиляция в Java имеет смысл.

Чтобы дополнить информацию в ответе Алексея Романова, которая все еще актуальна и действительна для Scala 2, я хотел бы добавить, что начиная с Scala 3 (он же Dotty, название его разработки), Scala сначала компилируется в промежуточное представление TASTy (которое добавляет типизированную информацию абстрактного синтаксического дерева в скомпилированные файлы классов — отсюда и название).

Вы можете увидеть презентацию о TASTy и ее роли в конвейере компилятора в этом интересном докладе на Scala Days 2019.

Как упоминалось в докладе, Dotty изначально предлагает возможность декомпиляции выходных данных компиляции (TASTy classfiles).

В качестве простого эксперимента давайте рассмотрим эту очень простую программу в файле Main.scala :

 object Main {

  def main(args: Array[String]): Unit = {
    println("hello, world")
  }

}
  

Выполнение dotc Main.scala на нем приводит к ожидаемому результату ( .class файл для Main класса, один для Main объекта и .tasty файл), который может быть отправлен обратно в (de) компилятор с -decompile опцией следующим образом:

 dotc -decompile Main
  

Вывод этой команды следующий:

 /** Decompiled from ./Main.tasty */
@scala.annotation.internal.SourceFile("Main.scala") object Main {
  def main(args: scala.Array[scala.Predef.String]): scala.Unit = scala.Predef.println("hello, world")
}
  

Вы можете следовать инструкциям здесь, чтобы начать работу с Dotty и выполнить тот же эксперимент, что и я, который был запущен с Dotty 0.27.0-RC1.