JavaRush /Java Blog /Random-ID /Ide IntelliJ: Dekompilasi, Kompilasi, Substitusi (atau ca...
Viacheslav
Level 3

Ide IntelliJ: Dekompilasi, Kompilasi, Substitusi (atau cara memperbaiki kesalahan orang lain)

Dipublikasikan di grup Random-ID
“Jangan menemukan kembali roda” adalah salah satu aturan utama untuk pekerjaan yang sukses dan efisien. Namun apa yang harus dilakukan jika Anda tidak ingin menemukan kembali roda Anda sendiri, tetapi roda kemudi orang lain ternyata bengkok dan rodanya berbentuk persegi? Tinjauan ini dimaksudkan untuk memberikan pengenalan sesingkat mungkin tentang teknik memperbaiki perpustakaan orang lain “sebagai upaya terakhir” dan bagaimana memperluasnya ke komputer Anda.
Ide IntelliJ: Dekompilasi, Kompilasi, Substitusi (atau cara memperbaiki kesalahan orang lain) - 1

Perkenalan

Kita semua menggunakan satu alat atau lainnya. Namun terkadang alat tersebut tidak sepenuhnya sesuai atau mengalami error. Berkat fitur bahasa Java, kita dapat memperbaiki perilaku alat jika kita membutuhkannya. Ada baiknya bila kita berkontribusi pada proyek dan mengirimkan pull request (Anda dapat membaca lebih lanjut di sini: “ GitHub - Berkontribusi pada proyek ”). Namun hal tersebut mungkin tidak langsung diterima, atau bahkan mungkin tidak diterima. Tapi untuk kebutuhan proyek itu diperlukan sekarang. Dan di sini, saya harap, artikel ini akan menunjukkan alat-alat yang tersedia bagi kita sebagai pengembang. Kita perlu melakukan langkah-langkah berikut yang akan kita bicarakan:
  • Siapkan aplikasi pengujian misalnya (menggunakan contoh proyek Hibernate)
  • Menemukan lokasi yang dapat diubah
  • Membuat perubahan
  • Menyebarkan repositori
Semua langkah di bawah ini diberikan untuk OS Windows, tetapi memiliki analog untuk sistem nix. Jadi Anda bisa mengulanginya jika perlu.

Persiapan Mata Pelajaran

Jadi, kita memerlukan proyek uji. Hibernasi sangat ideal bagi kami, karena... itu "bergaya, modis, modern." Saya tidak akan menjelaskan terlalu detail, karena... Artikel ini bukan tentang Hibernasi. Kami akan melakukan segalanya dengan cepat dan tepat sasaran. Dan kami, sebagai pengembang yang tepat, akan menggunakan sistem build. Misalnya Gradle juga cocok untuk kita, yang harus diinstal untuk artikel ini ( https://gradle.org/install/ ). Pertama, kita perlu membuat proyek. Maven memiliki arketipe untuk ini , dan Gradle memiliki plugin khusus untuk ini: Gradle Init . Jadi, buka baris perintah dengan cara apa pun yang Anda ketahui. Buat direktori untuk proyek tersebut, buka dan jalankan perintah:

mkdir javarush 
cd javarush 
gradle init --type java-application
Ide IntelliJ: Dekompilasi, Kompilasi, Substitusi (atau cara memperbaiki kesalahan orang lain) - 2
Sebelum mengimpor proyek, mari buat beberapa perubahan pada file yang menjelaskan cara pembuatannya. File ini disebut skrip build dan diberi nama build.gradle. Itu terletak di direktori tempat kita mengeksekusi gradle init. Oleh karena itu, kita cukup membukanya (misalnya di Windows dengan perintah start build.gradle). Kami menemukan blok " dependensi " di sana, mis. ketergantungan. Semua toples pihak ketiga yang akan kami gunakan dijelaskan di sini. Sekarang kita perlu memahami apa yang harus dijelaskan di sini. Mari kita pergi ke situs web Hibernate ( http://hibernate.org/ ). Kami tertarik pada Hibernasi ORM . Kami membutuhkan rilis terbaru. Di menu sebelah kiri ada subbagian “Rilis”. Pilih "stabil terbaru". Gulir ke bawah dan temukan “Implementasi inti (termasuk JPA)”. Sebelumnya, dukungan JPA perlu dihubungkan secara terpisah, tetapi sekarang semuanya menjadi lebih sederhana dan hanya satu ketergantungan yang cukup. Kita juga perlu bekerja dengan database menggunakan Hibernate. Untuk melakukan ini, mari kita ambil opsi paling sederhana - H2 Database . Pilihan sudah dibuat, berikut adalah ketergantungan kami:

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'
}
Bagus, apa selanjutnya? Kita perlu mengkonfigurasi Hibernate. Hibernate memiliki " Panduan Memulai ", tapi itu bodoh dan lebih merupakan penghalang daripada bantuan. Oleh karena itu, yuk langsung buka “ Panduan Pengguna ” seperti orang yang tepat. Di daftar isi kita melihat bagian “ Bootstrap ”, yang diterjemahkan sebagai “Bootstrapping”. Hanya apa yang Anda butuhkan. Banyak sekali kata-kata pintar yang tertulis disana, tapi intinya harus ada direktori META-INF di classpath, dan harus ada file persistence.xml. Menurut standar, classpath berisi direktori “resources”. Oleh karena itu, kami membuat direktori yang ditentukan: mkdir src\main\resources\META-INF Buat file persistence.xml di sana dan buka. Di dalam dokumentasi terdapat contoh "Contoh 268. File konfigurasi META-INF/persistence.xml" yang akan kita ambil isinya dan masukkan ke dalam file persistence.xml. Selanjutnya, luncurkan IDE dan impor proyek yang kita buat ke dalamnya. Sekarang kita perlu menyimpan sesuatu ke database. Ini adalah sesuatu yang disebut entitas. Entitas mewakili sesuatu dari apa yang disebut model domain. Dan di daftar isi, lihatlah, kita melihat “ 2. Model Domain ”. Kita lihat teksnya dan lihat di bab "2.1. Jenis pemetaan" contoh sederhana dari suatu entitas. Mari kita bahas sendiri, persingkat sedikit:
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;
    }
}
Sekarang kita memiliki kelas yang mewakili suatu entitas. Mari kembali ke persistence.xml dan perbaiki satu tempat di sana: Jika diindikasikan, classkami akan menunjukkan class kami entity.Contact. Hebat, yang tersisa hanyalah meluncurkannya. Mari kembali ke bab Bootstrap . Karena kami tidak memiliki server aplikasi yang akan memberi kami lingkungan EE khusus (yaitu lingkungan yang mengimplementasikan perilaku sistem tertentu untuk kami), kami bekerja di lingkungan SE. Untuk ini, hanya contoh "Contoh 269. Aplikasi EntityManagerFactory yang di-bootstrap" yang cocok untuk kita. Misalnya, mari kita lakukan ini:
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);
    }
}
Hore, subjek kita sudah siap. Saya tidak ingin menghilangkan bagian ini , karena... Untuk bab-bab berikutnya, disarankan untuk memahami bagaimana pokok bahasan kita muncul.

Menemukan Perilaku yang Dapat Dimodifikasi

Mari kita ganti inisialisasi bidang count bertipe BigInteger dan atur breakpoint di sana ( BreakPoint ). Setelah disisipkan pada baris yang diinginkan, hal ini dapat dilakukan dengan menggunakan Ctrl+F8 atau melalui menu Run -> Toggle Line Breakpoint. Kemudian kita jalankan metode utama kita di debug (Run -> Debug):
Ide IntelliJ: Dekompilasi, Kompilasi, Substitusi (atau cara memperbaiki kesalahan orang lain) - 3
Contoh yang sedikit kikuk, tapi katakanlah kita ingin mengubah jumlah ruang kueri saat startup. Seperti yang bisa kita lihat, sqlQuery kita adalah NativeQueryImpl. Klik Ctrl+N, tulis nama kelas, dan buka. Sehingga ketika kita masuk ke suatu kelas, kita akan dipindahkan ke tempat dimana kelas tersebut berada dan mengaktifkan autoscroll:
Ide IntelliJ: Dekompilasi, Kompilasi, Substitusi (atau cara memperbaiki kesalahan orang lain) - 4
Mari kita segera perhatikan bahwa Idea saat ini tidak mengetahui di mana menemukan kode sumber program (yaitu kode sumber). Oleh karena itu, dia dengan baik hati mendekompilasi konten dari file kelas untuk kami:
Ide IntelliJ: Dekompilasi, Kompilasi, Substitusi (atau cara memperbaiki kesalahan orang lain) - 5
Perhatikan juga bahwa di judul jendela IntelliJ Idea tertulis di mana Gradle menyimpan artefak untuk kita. Sekarang, mari masuk ke Idea jalur di mana artefak kita berada:
Ide IntelliJ: Dekompilasi, Kompilasi, Substitusi (atau cara memperbaiki kesalahan orang lain) - 6
Mari masuk ke direktori ini pada baris perintah menggunakan perintah cd way to каталогу. Saya akan segera membuat catatan: jika memungkinkan untuk membangun proyek dari sumber, lebih baik membangun dari sumber. Misalnya, kode sumber Hibernate tersedia di situs resminya. Lebih baik mengambilnya untuk versi yang diinginkan dan membuat semua perubahan di sana dan merakitnya menggunakan skrip build yang ditentukan dalam proyek. Saya menyajikan di artikel opsi paling buruk - ada toples, tetapi tidak ada kode sumber. Dan catatan nomor 2: Gradle bisa mendapatkan kode sumber menggunakan plugin. Lihat Cara mengunduh javadocs dan sumber jar menggunakan Gradle untuk detailnya .

Membuat perubahan

Kita perlu membuat ulang struktur direktori sesuai dengan paket tempat kelas yang kita ubah berada. Dalam hal ini: mkdir org\hibernate\query\internal, setelah itu kita membuat file di direktori ini NativeQueryImpl.java. Sekarang kita buka file ini dan salin semua konten kelas dari IDE di sana (yang sama dengan yang didekompilasi oleh Idea untuk kita). Ubah garis yang diperlukan. Misalnya:
Ide IntelliJ: Dekompilasi, Kompilasi, Substitusi (atau cara memperbaiki kesalahan orang lain) - 7
Sekarang, mari kita kompilasi filenya. Kami melakukan: javac org\hibernate\query\internal\NativeQueryImpl.java. Wah, tidak bisa begitu saja diambil dan dikompilasi tanpa error. Kami menerima banyak kesalahan Tidak Dapat Menemukan Simbol, karena... kelas yang bisa berubah terikat dengan kelas lain, yang biasanya ditambahkan oleh IntelliJ Idea ke jalur kelas untuk kita. Apakah Anda merasakan semua kegunaan IDE kami? =) Baiklah, kita tambahkan sendiri, kita juga bisa. Mari salin jalur untuk:
  • [1] - hibernasi-core-5.2.17.Final.jar
  • [2] - hibernasi-jpa-2.1-api-1.0.0.Final.jar
Seperti yang kami lakukan: Dalam tampilan “Proyek” di “Perpustakaan eksternal” kami menemukan toples yang diperlukan dan klik Ctrl+Shift+C. Sekarang mari kita buat dan jalankan perintah berikut: javac -cp [1];[2] org\hibernate\query\internal\NativeQueryImpl.java Hasilnya, file kelas baru akan muncul di sebelah file java, yang perlu diperbarui di file jar:
Ide IntelliJ: Dekompilasi, Kompilasi, Substitusi (atau cara memperbaiki kesalahan orang lain) - 8
Hore, sekarang Anda bisa melakukan pembaruan jar. Kita dapat dipandu oleh materi resmi : jar uf hibernate-core-5.2.17.Final.jar org\hibernate\query\internal\*.class Open IntelliJ Idea kemungkinan besar tidak akan mengizinkan Anda mengubah file. Oleh karena itu, sebelum melakukan pembaruan jar, kemungkinan besar Anda harus menutup Idea, dan setelah pembaruan, membukanya. Setelah ini, Anda dapat membuka kembali IDE dan menjalankan dubug lagi. Break Points tidak direset di antara restart IDE. Oleh karena itu, eksekusi program akan berhenti seperti sebelumnya. Voila, kami melihat cara kerja perubahan kami:
Ide IntelliJ: Dekompilasi, Kompilasi, Substitusi (atau cara memperbaiki kesalahan orang lain) - 9
Besar. Namun di sini muncul pertanyaan - karena apa? Hanya karena fakta bahwa ketika gradle membangun sebuah proyek, ia menganalisis blok dependensi dan repositori. Gradle memiliki build cache tertentu, yang terletak di lokasi tertentu (lihat “ Bagaimana cara menyetel lokasi cache gradle? ” Jika tidak ada ketergantungan pada cache, maka Gradle akan mendownloadnya dari repositori. Karena kita mengubah jar di repositori cache itu sendiri, lalu Gradle berpikir bahwa perpustakaan ada di dalam cache dan tidak memompa apa pun. Namun setiap pembersihan cache akan menyebabkan perubahan kita hilang. Ditambah lagi, tidak ada orang lain selain kita yang bisa pergi dan mengambilnya. Betapa merepotkannya , bukan? Apa yang harus dilakukan. Hmm, unduh dari repositori? Jadi kita memerlukan repositori kita, dengan preferensi dan penyairnya. Ini adalah langkah selanjutnya.

Menyebarkan repositori

Ada berbagai solusi gratis untuk menyebarkan repositori Anda: salah satunya adalah Artifactory , dan yang lainnya adalah Apache Archive . Artifactory terlihat modis, penuh gaya, modern, tetapi saya mengalami kesulitan dengannya, saya tidak ingin menempatkan artefak dengan benar dan menghasilkan metadata pakar yang salah. Oleh karena itu, secara tidak terduga bagi saya sendiri, versi Apache berfungsi untuk saya. Ternyata tidak begitu indah, tetapi berfungsi dengan baik. Di halaman unduh , cari versi Standalone dan buka kemasannya. Mereka memiliki " Mulai Cepat " mereka sendiri . Setelah peluncuran, Anda harus menunggu sampai alamatnya http://127.0.0.1:8080/#repositorylist. Setelah itu, pilih "Unggah Artefak":
Ide IntelliJ: Dekompilasi, Kompilasi, Substitusi (atau cara memperbaiki kesalahan orang lain) - 10
Klik "Mulai Unggah", lalu "Simpan File". Setelah ini, pesan sukses berwarna hijau akan muncul dan artefak akan tersedia di bagian “Jelajahi”. Ini harus dilakukan untuk file jar dan pom:
Ide IntelliJ: Dekompilasi, Kompilasi, Substitusi (atau cara memperbaiki kesalahan orang lain) - 11
Hal ini disebabkan oleh fakta bahwa dependensi hibernasi tambahan ditentukan dalam file pom. Dan kita hanya punya 1 langkah lagi - tentukan repositori di skrip build kita:

repositories {
    jcenter()
    maven {
        url "http://127.0.0.1:8080/repository/internal/"
    }
}
Dan karenanya, versi hibernasi kita akan menjadi: compile 'org.hibernate:hibernate-core:5.2.17.Final-JAVARUSH'. Itu saja, sekarang proyek kami menggunakan versi yang kami koreksi, dan bukan yang asli.

Kesimpulan

Sepertinya kita berkenalan. Saya harap itu menarik. “Trik” seperti itu jarang dilakukan, tetapi jika tiba-tiba persyaratan bisnis Anda menetapkan kondisi yang tidak dapat dipenuhi oleh perpustakaan yang Anda gunakan, Anda tahu apa yang harus dilakukan. Dan ya, berikut beberapa contoh yang dapat diperbaiki dengan cara ini:
  • Ada server web bernama Undertow. Hingga beberapa waktu, terdapat bug yang, saat menggunakan proxy, tidak memungkinkan kami mengetahui IP pengguna akhir.
  • Untuk saat ini, WildFly JPA menangani dengan cara tertentu suatu momen yang tidak diperhitungkan oleh spesifikasi, karena itu Pengecualian dilemparkan. Dan itu tidak dapat dikonfigurasi.
#Viacheslav
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION