JavaRush /Java Blog /Random-JA /IntelliJ のアイデア: 逆コンパイル、コンパイル、置換 (または他の人の間違いを修正する方法)
Viacheslav
レベル 3

IntelliJ のアイデア: 逆コンパイル、コンパイル、置換 (または他の人の間違いを修正する方法)

Random-JA グループに公開済み
「車輪の再発明をしない」は、仕事を効率的に成功させるための主要なルールの 1 つです。しかし、自分のハンドルを再発明したくないが、他の人のハンドルが曲がっていて、ホイールが四角いことが判明した場合はどうすればよいでしょうか? このレビューは、「最後の手段として」他の人のライブラリを修正する手法と、これを自分のコンピュータに拡張する方法をできるだけ簡単に紹介することを目的としています。
IntelliJ アイデア: 逆コンパイル、コンパイル、置換 (または他の人の間違いを修正する方法) - 1

導入

私たちは皆、何らかのツールを使用しています。ただし、ツールが完全に適切ではなかったり、エラーが発生したりする場合があります。Java 言語の機能のおかげで、必要に応じてツールの動作を修正できます。プロジェクトに貢献し、プル リクエストを送信するのは良いことです (詳細については、「GitHub - プロジェクトへの貢献」を参照してください)。しかし、すぐには受け入れられない、あるいは受け入れられない可能性もあります。しかし、プロジェクトのニーズにとって、それは今必要です。そして、この記事が私たち開発者が利用できるツールを示すことができれば幸いです。これから説明する次の手順を実行する必要があります。
  • たとえば、テスト アプリケーションを準備します (Hibernate プロジェクトの例を使用)
  • 変更可能な場所を見つける
  • 変化を起こす
  • リポジトリのデプロイ
以下のすべての手順は Windows OS を対象としていますが、nix システムでも同様の手順があります。したがって、必要に応じてそれらを繰り返すことができます。

被験者の準備

したがって、テストプロジェクトが必要です。Hibernate は私たちにとって理想的なものです。なぜなら... それは「スタイリッシュ、ファッショナブル、モダン」です。あまり詳しくは述べませんが、なぜなら... この記事は Hibernate に関するものではありません。すべてを迅速かつ的確に行います。そして私たちも、正規の開発者と同様に、ビルド システムを使用します。たとえば、この記事では Gradle をインストールする必要があります ( https://gradle.org/install/ )。まず、プロジェクトを作成する必要があります。Mavenには this のアーキタイプがあり、Gradle にはこれのための特別なプラグインGradle Initがあります。したがって、使い慣れた方法でコマンド ラインを開きます。プロジェクトのディレクトリを作成し、そこに移動してコマンドを実行します。

mkdir javarush 
cd javarush 
gradle init --type java-application
IntelliJ アイデア: 逆コンパイル、コンパイル、置換 (または他の人の間違いを修正する方法) - 2
プロジェクトをインポートする前に、ビルド方法を記述したファイルにいくつかの変更を加えてみましょう。このファイルはビルド スクリプトと呼ばれ、build.gradle という名前が付けられます。これは、gradle init を実行したディレクトリにあります。したがって、単にそれを開きます (たとえば、Windows では start build.gradle コマンドを使用します)。そこで「 dependency 」ブロックを見つけます。依存関係。ここでは、使用するすべてのサードパーティの jar について説明します。ここで何を説明するかを理解する必要があります。Hibernate Web サイト ( http://hibernate.org/ ) にアクセスしてみましょう。私たちはHibernate ORMに興味があります。最新のリリースが必要です。左側のメニューには「リリース」サブセクションがあります。「最新の安定版」を選択します。下にスクロールして「コア実装 (JPA を含む)」を見つけます。以前は、JPA サポートを個別に接続する必要がありましたが、現在はすべてが簡単になり、依存関係は 1 つだけで十分です。Hibernate を使用してデータベースを操作する必要もあります。これを行うには、最も単純なオプションであるH2 Databaseを使用してみましょう。選択が行われました。依存関係は次のとおりです。

dependencies {
    // Базовая зависимость для Hibernate (новые версии включают и JPA)
    compile 'org.hibernate:hibernate-core:5.2.17.Final'
    // База данных, к которой мы будем подключаться
    compile 'com.h2database:h2:1.4.197'
    // Use JUnit test framework
    testCompile 'junit:junit:4.12'
}
すごいですね、次は何ですか?Hibernate を設定する必要があります。Hibernate には「Getting Started Guide」がありますが、それは愚かで、役立つというよりはむしろ邪魔です。したがって、適切な人々のように、すぐに「ユーザーガイド」に進みましょう。目次には「Bootstrap」というセクションがあります。これは「ブートストラップ」と訳されます。必要なものだけを。そこには多くの気の利いた言葉が書かれていますが、重要なのは、クラスパス上に META-INF ディレクトリが存在し、persistence.xml ファイルが存在する必要があるということです。標準に従って、クラスパスには「resources」ディレクトリが含まれます。したがって、指定されたディレクトリを作成します。mkdir src\main\resources\META-INF そこにpersistence.xml ファイルを作成して開きます。ドキュメントには例「例 268. META-INF/persistence.xml 設定ファイル」があり、そこから内容を取得して、persistence.xml ファイルに挿入します。次に、IDE を起動し、作成したプロジェクトをそこにインポートします。次に、何かをデータベースに保存する必要があります。これはエンティティと呼ばれるものです。エンティティは、いわゆるドメイン モデルからのものを表します。そして目次には、なんと「2. ドメイン モデル」が表示されています。テキストを下に進み、「2.1. マッピング タイプ」の章でエンティティの簡単な例を見てみましょう。少し短くしてみましょう。
package entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity(name = "Contact")
public class Contact {

    @Id
    @GeneratedValue
    private Integer id;

    private String name;

    public Contact(String name) {
        this.name = name;
    }
}
これで、エンティティを表すクラスができました。persistence.xml に戻って、そこを 1 か所修正しましょう。示されている箇所には、classクラスを示しますentity.Contact。素晴らしいです。あとは起動するだけです。ブートストラップの章に戻りましょう。特別な EE 環境 (つまり、特定のシステム動作を実装する環境) を提供してくれるアプリケーション サーバーがないため、SE 環境で作業します。これには、「例 269. アプリケーションがブートストラップされた EntityManagerFactory」の例のみが適しています。たとえば、次のようにしてみましょう。
public class App {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("CRM");
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        Contact contact = new Contact("Vasya");
        em.persist(contact);
        em.getTransaction().commit();
        Query sqlQuery = em.createNativeQuery("select count(*) from contact");
        BigInteger count = (BigInteger) sqlQuery.getSingleResult();
        emf.close();
        System.out.println("Entiries count: " + count);
    }
}
万歳、主題の準備は完了です。この部分は省略したくなかったので... 次の章では、この主題がどのようにして生まれたのかを理解することをお勧めします。

変更可能な動作を見つける

BigInteger 型の count フィールドの初期化の代わりに、そこにブレークポイント ( BreakPoint ) を設定しましょう。目的の行に挿入したら、Ctrl+F8 を使用するか、メニューの [実行] -> [行ブレークポイントの切り替え] を使用してこれを行うことができます。次に、デバッグで main メソッドを実行します ([実行] -> [デバッグ])。
IntelliJ アイデア: 逆コンパイル、コンパイル、置換 (または他の人の間違いを修正する方法) - 3
少し不格好な例ですが、起動時にクエリ スペースの数を変更したいとします。ご覧のとおり、sqlQuery は NativeQueryImpl です。をクリックしCtrl+N、クラスの名前を入力して、そのクラスに移動します。クラスに行くときに、このクラスがある場所に転送され、自動スクロールがオンになるようにします。
IntelliJ アイデア: 逆コンパイル、コンパイル、置換 (または他の人の間違いを修正する方法) - 4
Idea は現在、プログラムのソース コード (ソース コード) をどこで見つけられるかわからないことにすぐに注意してください。そこで、彼女は親切にもクラス ファイルの内容を逆コンパイルしてくれました。
IntelliJ アイデア: 逆コンパイル、コンパイル、置換 (または他の人の間違いを修正する方法) - 5
IntelliJ Idea ウィンドウのタイトルには、Gradle がアーティファクトを保存する場所が記載されていることにも注意してください。次に、Idea でアーティファクトが配置されているパスを取得しましょう。
IntelliJ アイデア: 逆コンパイル、コンパイル、置換 (または他の人の間違いを修正する方法) - 6
コマンドラインで コマンド を使用して、このディレクトリに移動しましょうcd way to каталогу。すぐにメモします。ソースからプロジェクトをビルドできる場合は、ソースからビルドする方が良いでしょう。たとえば、Hibernate のソース コードは公式 Web サイトから入手できます。目的のバージョンを選択し、そこにすべての変更を加え、プロジェクトで指定されているビルド スクリプトを使用してアセンブルすることをお勧めします。この記事では、最も恐ろしいオプションを紹介します。jar はありますが、ソース コードはありません。注意点 2: Gradle はプラグインを使用してソース コードを取得できます。詳細については、「Gradle を使用して JAR の Javadoc とソースをダウンロードする方法」を参照してください。

変化を起こす

変更するクラスが配置されているパッケージに従ってディレクトリ構造を再作成する必要があります。この場合: mkdir org\hibernate\query\internal、その後、このディレクトリにファイルを作成しますNativeQueryImpl.java。次に、このファイルを開いて、そこにある IDE (Idea が逆コンパイルしたものと同じもの) からクラスのすべてのコンテンツをコピーします。必要な行を変更します。例えば:
IntelliJ アイデア: 逆コンパイル、コンパイル、置換 (または他の人の間違いを修正する方法) - 7
それでは、ファイルをコンパイルしましょう。私たちは次のことを行いますjavac org\hibernate\query\internal\NativeQueryImpl.java。うわー、それをそのまま受け取ってエラーなしでコンパイルすることはできません。「シンボルが見つかりません」エラーを大量に受け取りました。理由は... 可変クラスは他のクラスに関連付けられており、通常は IntelliJ Idea によってクラスパスに追加されます。私たちの IDE の有用性は十分に感じられましたか? =) そうですね、自分で追加しましょう。私たちでもできます。次のパスをコピーしましょう。
  • [1] - hibernate-core-5.2.17.Final.jar
  • [2] - hibernate-jpa-2.1-api-1.0.0.Final.jar
先ほどと同じように、「外部ライブラリ」の「プロジェクト」ビューで必要な jar を見つけて、 をクリックしますCtrl+Shift+C。次に、次のコマンドを作成して実行しましょう。 javac -cp [1];[2] org\hibernate\query\internal\NativeQueryImpl.java その結果、新しいクラス ファイルが Java ファイルの隣に表示されます。これは、jar ファイル内で更新する必要があります。
IntelliJ アイデア: 逆コンパイル、コンパイル、置換 (または他の人の間違いを修正する方法) - 8
これで、jar の更新を実行できるようになりました。公式資料を参照してください。Open jar uf hibernate-core-5.2.17.Final.jar org\hibernate\query\internal\*.class IntelliJ Idea では、ファイルの変更が許可されない可能性が高くなります。したがって、jar の更新を実行する前に Idea を閉じ、更新後に Idea を開く必要がある可能性があります。この後、IDE を再度開いて dubug を再度実行できます。ブレーク ポイントは、IDE の再起動の間にリセットされません。したがって、プログラムの実行は以前の位置で停止します。ほら、変更がどのように機能するかがわかります。
IntelliJ アイデア: 逆コンパイル、コンパイル、置換 (または他の人の間違いを修正する方法) - 9
素晴らしい。しかし、ここで疑問が生じます - 何が原因でしょうか?単純に、gradle がプロジェクトをビルドするときに、依存関係とリポジトリ ブロックを分析するためです。Gradle には、特定の場所にある特定のビルド キャッシュがあります (「Gradle キャッシュの場所を設定する方法」を参照) キャッシュに依存関係がない場合、Gradle はそれをリポジトリからダウンロードします。キャッシュ自体をキャッシュすると、Gradle はライブラリがキャッシュ内にあると認識し、何も吐き出しません。しかし、キャッシュをクリアすると、変更内容が失われます。さらに、私たち以外の誰も、それらを取りに行くことはできません。どれほど不便でしょう。そうですよね? どうすればいいですか。うーん、リポジトリからダウンロードしますか? それで、設定と詩人を備えたリポジトリが必要です。これが次のステップです。

リポジトリのデプロイ

リポジトリをデプロイするためのさまざまな無料ソリューションがあります。そのうちの 1 つはArtifactory、もう 1 つはApache Archiveです。Artifactory はファッショナブルでスタイリッシュでモダンに見えますが、私には問題があり、アーティファクトを正しく配置したくなく、誤った Maven メタデータが生成されました。したがって、私自身にとっては予想外でしたが、Apache バージョンがうまくいきました。それほど美しくはありませんでしたが、確実に機能します。ダウンロードページで、スタンドアロン バージョンを探して解凍します。独自の「クイックスタート」があります。起動後、アドレスが表示されるまで待つ必要がありますhttp://127.0.0.1:8080/#repositorylist。その後、「アーティファクトのアップロード」を選択します。
IntelliJ アイデア: 逆コンパイル、コンパイル、置換 (または他の人の間違いを修正する方法) - 10
「アップロードの開始」をクリックし、「ファイルを保存」をクリックします。この後、緑色の成功メッセージが表示され、「参照」セクションでアーティファクトが利用可能になります。これは、jar ファイルと pom ファイルに対して行う必要があります。
IntelliJ アイデア: 逆コンパイル、コンパイル、置換 (または他の人の間違いを修正する方法) - 11
これは、追加の Hibernate 依存関係が pom ファイルで指定されているためです。残っているステップは 1 つだけです。ビルド スクリプトでリポジトリを指定します。

repositories {
    jcenter()
    maven {
        url "http://127.0.0.1:8080/repository/internal/"
    }
}
したがって、休止状態のバージョンは次のようになりますcompile 'org.hibernate:hibernate-core:5.2.17.Final-JAVARUSH'。これで、私たちのプロジェクトでは、元のバージョンではなく、修正したバージョンが使用されるようになりました。

結論

知り合いになったようです。面白かったら幸いです。このような「トリック」が行われることはめったにありませんが、ビジネス要件により、使用するライブラリが満たせない条件が突然設定された場合、どうすればよいかはわかります。はい、この方法で修正できる例をいくつか示します。
  • Undertow という Web サーバーがあります。しばらく前まで、プロキシを使用するとエンド ユーザーの IP を知ることができないというバグがありました。
  • 当面の間、WildFly JPA は、この例外がスローされたため、仕様で考慮されていないある瞬間を特定の方法で処理しました。そしてそれは設定可能ではありませんでした。
#ヴィアチェスラフ
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION