"Та не винайти ти велосипед" - одне з головних правил успішної та ефективної роботи. Але що робити, коли свій велосипед винаходити не хочеться, а у чужого кермо виявилося кривим, а колеса квадратними? Даний огляд призначений для можливості короткого ознайомлення з прийомом виправлення в чужих бібліотеках "на крайній випадок" і про те, як цю справу поширити далі свого комп'ютера.
Перш ніж виконувати імпорт проекту, внесемо деякі зміни до файлу, який описує, яким чином потрібно виконувати збірку. Цей файл називається build script'ом і має ім'я build.gradle. Знаходиться він у тому каталозі, де ми виконали gradle init. Тому просто відкриваємо його (наприклад, у windows командою start build.gradle). Знаходимо там блок " dependencies ", тобто. залежності. Тут описуються всі сторонні jar, які ми будемо використовувати. Тепер слід зрозуміти, що тут описувати. Перейдемо на сайт Hibernate ( http://hibernate.org/ ). Нас цікавить Hibernate ORM. Нам потрібний останній реліз. У меню зліва є підрозділ "Releases". Вибираємо "latest stable". Промотуємо вниз і знаходимо "Core implementation (includes JPA)". Раніше потрібно було підтримувати JPA окремо, але тепер все стало простіше і достатньо лише однієї залежності. Також нам знадобиться за допомогою Hibernate працювати з базою даних. Для цього візьмемо найпростіший варіант – H2 Database . Вибір зроблений, ось наші залежності:
Трохи незграбний приклад, але, скажімо, ми хочемо змінити кількість query spaces при старті. Як бачимо, наш sqlQuery це NativeQueryImpl. Натискаємо
Відразу зауважимо, що Idea не знає зараз, де можна знайти вихідний код програми (вихідники, тобто). Тому вона милостиво декомпілювала для нас із class файлу вміст:
Зауважимо також, що у заголовку вікна IntelliJ Idea пишеться, де Gradle зберігає для нас артефакт. Тепер отримаємо в Idea шлях, де лежить наш артефакт:
Перейдемо в цей каталог у командному рядку за допомогою команди
Тепер компілюємо файл. Виконуємо:
Ура тепер можна виконати jar update. Можемо керуватися офіційними матеріалами :
Чудово. Але тут постає питання – завдяки чому? Просто завдяки тому, що коли gradle збирає проект, він аналізує блок dependencies та repositories. У гредла є якийсь build cache, який лежить у певному місці (див. « How to set gradle cache location? ». Якщо в кеші немає залежності, то Gradle її скачає з репозиторію. Оскільки ми змінювали jar у самому кеші, то Gradle думає, що в кеші бібліотека є і нічого не викачує, але будь-яке очищення кешу призведе до того, що наші зміни пропадуть, плюс, ніхто, крім нас, не може просто взяти і отримати їх, скільки незручностей, чи не так? Хм, скачує з репозиторію?Отже, нам потрібен наш репозиторій, з преферансом та поетесами, про це наступний етап.
Натискаємо "Start Upload", а після "Save Files". Після цього з'явиться зелене повідомлення про успішність і артефакт стане доступним у розділі "Browse". Так треба зробити для jar та для pom файлів:
Це з тим, що у pom файлі прописані додаткові залежності хибернейта. А нам залишилося лише 1 крок – вказати репозиторій у нашому білд скрипті:
Вступ
Усі ми користуємося тими чи іншими інструментами. Але іноді інструменти підходять не до кінця або мають помилки. Завдяки особливостям мови Java ми можемо виправити поведінку інструментів там, де це потрібно. Добре, коли ми вносимо свій внесок проекти і надсилаємо пулл реквести (докладніше можна прочитати тут: « GitHub – Внесення власного вкладу до проектів »). Але приймати їх можуть не одразу, а можуть навіть не прийняти. Але для потреб проекту потрібно ось зараз. І тут, сподіваюся, ця стаття покаже доступні нам, як розробнику, гроші. Нам знадобиться виконати такі дії, про які ми говоритимемо:- Підготувати випробуваний додаток для прикладу (на прикладі Hibernate проекту)
- Пошук місця, що змінюється
- Виконання зміни
- Розгортання репозиторію
Підготовка випробуваного
Отже, нам потрібний піддослідний проект. Нам ідеально підійде Hibernate, т.к. це "стильно, модно, сучасно". Не особливо вдаватися до деталей, т.к. стаття не про Hibernate Робитимемо все швидко і у справі. І будемо, як правильні розробники, використовувати систему збирання. Наприклад, нам також підійде Gradle, який для цієї статті повинен бути встановлений ( https://gradle.org/install/ ). Спочатку нам потрібно створити проект. У Maven'а для цього є архетипи , а у Gradle для цього є особливий плагін: Gradle Init . Отже, відкриваємо командний рядок будь-яким відомим вам способом. Створюємо каталог для проекту, переходимо до нього та виконуємо команду:
mkdir codegym
cd codegym
gradle init --type java-application
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 ", але він безглуздий і більше заважає, ніж допомагає. Тому підемо як правильні люди відразу в " User Guide ". У змісті бачимо розділ " Bootstrap ", що перекладається як "Початкове завантаження". Те що треба. Там написано багато розумних слів, але сенс у тому, що на classpath має бути каталог META-INF, а там файл persistence.xml. На classpath за стандартом потрапляє каталог "resources". Тому створюємо вказаний каталог:mkdir src\main\resources\META-INF
Створюємо там файл persistence.xml та відкриваємо його. Там же в документації є приклад "Example 268. META-INF/persistence.xml configuration file" з якого ми візьмемо вміст і вставимо у файл persistence.xml. Далі запускаємо IDE та імпортуємо до неї наш створений проект. Тепер нам треба щось зберігати у базу. Це щось називається сутністю. Сутності представляють щось із так званої доменної моделі. І в змісті, про диво, бачимо « 2. Domain Model ». Спускаємося нижче за текстом і бачимо у розділі "2.1. Mapping types" простий приклад сутності. Забираємо його до себе, трохи скоротивши:
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 і поправимо там одне місце: Там де вказано class
вкажемо свій клас entity.Contact
. Добре, залишилося запуститися. Повертаємося в розділ « Bootstrap ». Так як у нас немає сервера додатків, який нам надасть особливе EE оточення (тобто оточення, яке реалізує для нас певну поведінку системи), ми працюємо в SE оточенні. Для нього нам підійде лише приклад "Example 269. Application bootstrapped 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);
}
}
Ура, наш випробуваний готовий. Цю частину не хотів опускати , т.к. для наступних розділів бажано розуміти те, як з'явився наш випробуваний.
Пошук змінної поведінки
Давайте станемо місце ініціалізації поля count типу BigInteger і поставимо там точки зупинки ( BreakPoint ). Вставши на потрібному рядку це можна зробити за допомогою Ctrl+F8 або через меню Run -> Toggle Line Breakpoint. Після чого запускаємо наш main метод у дебазі (Run -> Debug):Ctrl+N
, пишемо назву класу, переходимо до нього. Щоб при перехід у клас нас перекидало те місце, де лежить цей клас включив автоскрол:
cd шлях до каталогу
. Відразу зроблю зауваження: якщо є можливість зібрати проект із вихідних, краще збирати з вихідних. Наприклад, вихідний код Hibernate доступний на офіційному сайті. Краще забрати його для потрібної версії і зробити всі зміни там і зібратися за допомогою скриптів збирання, які вказані у проекті. Я ж наводжу у статті найжахливіший варіант – є jar, а вихідного коду немає. І зауваження номер 2: Gradle може отримати вихідний код за допомогою плагінів. Докладніше див. « How to download javadocs and sources for jar using Gradle .
Виконання зміни
Нам потрібно відтворити структуру каталогів відповідно до того, в якому пакеті лежить клас, що змінюється. У цьому випадку:mkdir org\hibernate\query\internal
, після чого створюємо в цьому каталозі файл NativeQueryImpl.java
. Тепер відкриваємо даний файл і копіюємо туди весь вміст класу з IDE (те саме, яке для нас декомпілювала Idea). Змінюємо потрібні рядки. Наприклад:
javac org\hibernate\query\internal\NativeQueryImpl.java
. Потрібно ж, не можна просто взяти і скомпілювати без помилок. Набули купу помилок Cannot Find Symbol, т.к. змінюваний клас зав'язаний інші класи, які зазвичай IntelliJ Idea за нас додає в classpath. Чи відчуваєте всю корисність наших IDE? =) Що ж, давайте додамо самі, ми теж можемо. Скопіюємо окремо в блокнот шляху:
- [1] - hibernate-core-5.2.17.Final.jar
- [2] - hibernate-jpa-2.1-api-1.0.0.Final.jar
Ctrl+Shift+C
. Тепер сформуємо та виконаємо таку команду: javac -cp [1];[2] org\hibernate\query\internal\NativeQueryImpl.java
В результаті поряд з java файлом з'являться нові class файли, які потрібно оновити у jar файлі:
jar uf hibernate-core-5.2.17.Final.jar org\hibernate\query\internal\*.class
Відкрита IntelliJ Idea, швидше за все, не дасть змінювати файли. Тому до виконання jar update, швидше за все, доведеться закрити Idea, а після оновлення – відкрити. Після цього можна знову відкриваємо IDE, знову виконуємо dubug. Break Points не скидаються між перезапусками IDE. Тому виконання програми зупиниться там, де й раніше. Вуаля, ми бачимо, як працюють наші зміни:
Розгортання репозиторію
Для розгортання свого репозиторію існують різні безкоштовні рішення: одне з них Artifactory , а інше – Apache Archive . Артифактори виглядає модно, стильно, сучасно, але з ним у мене виникли труднощі, ніяких не хотів правильно розміщувати артефакти і генерував помилкові метадані. Тому, несподівано для себе, у мене запрацював апачевський варіант. Він виявився не таким гарним, зате працює надійно. На сторінці завантаження шукаємо Standalone версію, розпаковуємо. У них є свій " Quick Start ". Після запуску слід дочекатися, коли за адресаоюhttp://127.0.0.1:8080/#repositorylist
. Після цього вибираємо "Upload Artifact":
repositories {
jcenter()
maven {
url "http://127.0.0.1:8080/repository/internal/"
}
}
І, відповідно, версія нашого хібернейту стане: compile 'org.hibernate:hibernate-core:5.2.17.Final-CODEGYM'
. Ось і все тепер наш проект використовує виправлений нами варіант, а не початковий.
Висновок
От наче й ознайомабось. Сподіваюся, було цікаво. Подібні "трюки" робляться рідко, але якщо раптом ваші бізнес вимоги поставлять умови, які не можуть задовольнити бібліотеки, що використовуються - ви знаєте що робити. І так, ось кілька прикладів, що може так виправлятися:- Є такий веб-сервер Undertow. До деякого часу був баг, який при використанні проксі не давав дізнатися про IP кінцевого користувача.
- До певного часу WildFly JPA певним чином обробляв один не врахований специфікацією момент, через що сипалися Exception. І це не налаштовувалося.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ