JavaRush /Java Blog /Random-KO /IntelliJ 아이디어: 디컴파일, 컴파일, 대체(또는 다른 사람의 실수를 수정하는 방법)
Viacheslav
레벨 3

IntelliJ 아이디어: 디컴파일, 컴파일, 대체(또는 다른 사람의 실수를 수정하는 방법)

Random-KO 그룹에 게시되었습니다
"바퀴를 재발명하지 마십시오"는 성공적이고 효율적인 작업을 위한 주요 규칙 중 하나입니다. 하지만 자신의 바퀴를 재발명하고 싶지 않지만 다른 사람의 핸들이 비뚤어지고 바퀴가 정사각형인 경우 어떻게 해야 합니까? 이 리뷰는 "최후의 수단"으로 다른 사람의 라이브러리를 수정하는 기술과 이 문제를 컴퓨터 외부로 확장하는 방법에 대해 가능한 한 간략하게 소개하기 위한 것입니다.
IntelliJ 아이디어: 디컴파일, 컴파일, 대체(또는 다른 사람의 실수를 수정하는 방법) - 1

소개

우리 모두는 하나의 도구 또는 다른 도구를 사용합니다. 그러나 도구가 완전히 적합하지 않거나 오류가 있는 경우도 있습니다. Java 언어의 기능 덕분에 필요한 곳에서 도구의 동작을 수정할 수 있습니다. 프로젝트에 기여하고 끌어오기 요청을 보내는 것은 좋습니다(자세한 내용은 " GitHub - 프로젝트에 기여 "에서 확인할 수 있습니다). 그러나 즉시 받아들여지지 않을 수도 있고, 심지어 받아들여지지 않을 수도 있습니다. 그러나 프로젝트의 필요에 따라 지금은 필요합니다. 그리고 여기서 이 기사가 개발자로서 우리가 사용할 수 있는 도구를 보여줄 수 있기를 바랍니다. 우리가 이야기할 다음 단계를 수행해야 합니다.
  • 예를 들어 테스트 애플리케이션 준비(Hibernate 프로젝트의 예 사용)
  • 변경 가능한 위치 찾기
  • 변경하기
  • 저장소 배포
아래의 모든 단계는 Windows OS에 대해 제공되지만 nix 시스템에도 유사합니다. 따라서 필요한 경우 반복할 수 있습니다.

과목 준비

따라서 테스트 프로젝트가 필요합니다. 최대 절전 모드는 우리에게 이상적입니다. 왜냐하면... 그것은 "세련되고 패셔너블하며 현대적"입니다. 너무 자세히 설명하지는 않겠습니다. 왜냐면... 이 기사는 최대 절전 모드에 관한 것이 아닙니다. 우리는 모든 것을 신속하고 정확하게 처리할 것입니다. 그리고 우리는 적절한 개발자처럼 빌드 시스템을 사용할 것입니다. 예를 들어 Gradle도 우리에게 적합하므로 이 기사( https://gradle.org/install/ ) 에서는 Gradle을 설치해야 합니다 . 먼저 프로젝트를 생성해야 합니다. Maven에는 이에 대한 원형이 있고 Gradle에는 이를 위한 특별한 플러그인인 Gradle Init 이 있습니다 . 따라서 알려진 방식으로 명령줄을 엽니다. 프로젝트용 디렉터리를 만들고 해당 디렉터리로 이동하여 다음 명령을 실행합니다.

mkdir javarush 
cd javarush 
gradle init --type java-application
IntelliJ 아이디어: 디컴파일, 컴파일, 대체(또는 다른 사람의 실수를 수정하는 방법) - 2
프로젝트를 가져오기 전에 빌드 방법을 설명하는 파일을 일부 변경해 보겠습니다. 이 파일을 빌드 스크립트 라고 하며 이름은 build.gradle입니다. gradle init를 실행한 디렉터리에 있습니다. 따라서 간단히 엽니다(예: Windows에서는 start build.gradle 명령을 사용하여). 거기에서 " 종속성 " 블록을 찾습니다 . 의존성. 우리가 사용할 모든 타사 jar는 여기에 설명되어 있습니다. 이제 여기서 설명할 내용을 이해해야 합니다. Hibernate 웹사이트( http://hibernate.org/ ) 로 가보자 . 우리는 Hibernate ORM 에 관심이 있습니다 . 최신 릴리스가 필요합니다. 왼쪽 메뉴에는 "릴리스" 하위 섹션이 있습니다. "최신 안정"을 선택하십시오. 아래로 스크롤하여 "핵심 구현(JPA 포함)"을 찾습니다. 이전에는 JPA 지원을 별도로 연결해야 했지만 이제는 모든 것이 더 단순해지고 하나의 종속성만으로 충분합니다. 우리는 또한 Hibernate를 사용하여 데이터베이스로 작업해야 할 것입니다. 이를 위해 가장 간단한 옵션인 H2 데이터베이스를 선택해 보겠습니다 . 선택이 이루어졌습니다. 종속성은 다음과 같습니다.

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에는 " 시작하기 가이드 "가 있지만 그것은 어리석고 도움이 되기보다는 방해가 됩니다. 그러니 딱 맞는 분들처럼 바로 " 사용설명서 " 로 가보겠습니다 . 목차에는 " 부트스트랩 "으로 번역되는 "부트스트랩" 섹션이 있습니다. 당신에게 필요한 것. 거기에 스마트한 단어들이 많이 쓰여 있는데, 요점은 클래스패스에 META-INF 디렉터리가 있어야 하고, persistence.xml 파일이 있어야 한다는 것이다. 표준에 따르면 클래스 경로에는 "resources" 디렉터리가 포함되어 있습니다. 따라서 지정된 디렉터리를 생성합니다. mkdir src\main\resources\META-INF 거기에 persistence.xml 파일을 생성하고 엽니다. 문서에는 내용을 가져와 persistence.xml 파일에 삽입할 "예제 268. META-INF/persistence.xml 구성 파일" 예제가 있습니다. 다음으로 IDE를 실행하고 생성된 프로젝트를 IDE로 가져옵니다. 이제 데이터베이스에 무언가를 저장해야 합니다. 이것은 엔터티라고 불리는 것입니다. 엔터티는 소위 ​​도메인 모델의 일부를 나타냅니다. 그리고 목차를 보면 “ 2. Domain Model ”이 보입니다. 텍스트 아래로 내려가 "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로 돌아가서 한 곳을 수정해 보겠습니다. 표시된 곳에는 class클래스를 표시합니다 entity.Contact. 좋습니다. 이제 출시만 남았습니다. Bootstrap 장 으로 돌아가 보겠습니다 . 특별한 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을 사용하거나 메뉴 실행 -> 줄 중단점 전환을 통해 수행할 수 있습니다. 그런 다음 디버그에서 기본 메서드를 실행합니다(실행 -> 디버그).
IntelliJ 아이디어: 디컴파일, 컴파일, 대체(또는 다른 사람의 실수를 수정하는 방법) - 3
약간 서투른 예이지만 시작 시 쿼리 공간의 수를 변경하고 싶다고 가정해 보겠습니다. 보시다시피 sqlQuery는 NativeQueryImpl입니다. 을 클릭하고 Ctrl+N, 수업명을 적고 해당 수업으로 이동합니다. 따라서 수업에 가면 이 수업이 있는 곳으로 이동하고 자동 스크롤을 켭니다.
IntelliJ 아이디어: 디컴파일, 컴파일, 대체(또는 다른 사람의 실수를 수정하는 방법) - 4
Idea는 현재 프로그램의 소스 코드(소스 코드)를 어디에서 찾을 수 있는지 즉시 알 수 없습니다. 따라서 그녀는 친절하게도 우리를 위해 클래스 파일의 내용을 디컴파일했습니다.
IntelliJ 아이디어: 디컴파일, 컴파일, 대체(또는 다른 사람의 실수를 수정하는 방법) - 5
또한 IntelliJ Idea 창 제목에는 Gradle이 아티팩트를 저장하는 위치가 기록되어 있습니다. 이제 Idea에 아티팩트가 있는 경로를 입력해 보겠습니다.
IntelliJ 아이디어: 디컴파일, 컴파일, 대체(또는 다른 사람의 실수를 수정하는 방법) - 6
명령줄에서 명령을 사용하여 이 디렉터리로 이동해 보겠습니다 cd way to каталогу. 바로 메모해 두겠습니다. 소스에서 프로젝트를 빌드하는 것이 가능하다면 소스에서 빌드하는 것이 더 좋습니다. 예를 들어, Hibernate 소스 코드는 공식 웹사이트에서 사용할 수 있습니다. 원하는 버전에 맞게 선택하여 거기에서 모든 변경을 수행하고 프로젝트에 지정된 빌드 스크립트를 사용하여 어셈블하는 것이 좋습니다. 나는 기사에서 가장 끔찍한 옵션을 제시합니다. 항아리는 있지만 소스 코드는 없습니다. 참고 2: Gradle은 플러그인을 사용하여 소스 코드를 얻을 수 있습니다. 자세한 내용은 Gradle을 사용하여 jar용 javadoc 및 소스를 다운로드하는 방법을 참조하세요 .

변경하기

변경하려는 클래스가 어떤 패키지에 있는지에 따라 디렉터리 구조를 다시 만들어야 합니다. 이 경우: mkdir org\hibernate\query\internal, 그 후에 이 디렉토리에 파일을 생성합니다 NativeQueryImpl.java. 이제 이 파일을 열고 IDE에서 클래스의 모든 내용을 복사합니다(Idea가 우리를 위해 디컴파일한 것과 동일). 필요한 줄을 변경하십시오. 예를 들어:
IntelliJ 아이디어: 디컴파일, 컴파일, 대체(또는 다른 사람의 실수를 수정하는 방법) - 7
이제 파일을 컴파일해 보겠습니다. 우리는하다: javac org\hibernate\query\internal\NativeQueryImpl.java. 와, 그냥 가져와서 오류 없이 컴파일할 수는 없군요. 우리는 Cannot Find Symbol 오류를 많이 받았습니다. 왜냐하면... 변경 가능한 클래스는 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 업데이트를 수행할 수 있습니다. 공식 자료를 참조할 수 있습니다 . jar uf hibernate-core-5.2.17.Final.jar org\hibernate\query\internal\*.class Open IntelliJ Idea에서는 파일 변경을 허용하지 않을 가능성이 높습니다. 따라서 jar 업데이트를 수행하기 전에 Idea를 닫고 업데이트 후에 열어야 할 가능성이 높습니다. 그런 다음 IDE를 다시 열고 dubug를 다시 실행할 수 있습니다. IDE를 다시 시작할 때 중단점은 재설정되지 않습니다. 따라서 프로그램 실행은 이전 위치에서 중지됩니다. 짜잔, 변경 사항이 어떻게 작동하는지 살펴보겠습니다.
IntelliJ 아이디어: 디컴파일, 컴파일, 대체(또는 다른 사람의 실수를 수정하는 방법) - 9
엄청난. 그러나 여기서 질문이 발생합니다. 무엇 때문에? Gradle이 프로젝트를 빌드할 때 종속성과 저장소 블록을 분석한다는 사실 때문입니다. Gradle에는 특정 위치에 있는 특정 빌드 캐시가 있습니다(" Gradle 캐시 위치를 설정하는 방법 " 참조). 캐시에 종속성이 없으면 Gradle은 저장소에서 해당 캐시를 다운로드합니다. Gradle은 라이브러리가 캐시에 있다고 생각하고 아무것도 펌핑하지 않습니다. 그러나 캐시를 지우면 변경 사항이 손실됩니다. 게다가 우리 외에는 아무도 가서 가져올 수 없습니다. 얼마나 불편합니까? , 그렇죠? 해야 할 일. 흠, 저장소에서 다운로드합니까? 따라서 선호도와 시가 포함된 저장소가 필요합니다. 이것이 다음 단계입니다.

저장소 배포

저장소 배포를 위한 다양한 무료 솔루션이 있습니다. 그 중 하나 는 Artifactory 이고 다른 하나는 Apache Archive 입니다 . Artifactory는 패셔너블하고 스타일리시하며 현대적이지만 어려움을 겪었고 아티팩트를 올바르게 배치하고 싶지 않았으며 잘못된 Maven 메타데이터를 생성했습니다. 따라서 예기치 않게 Apache 버전이 저에게 효과적이었습니다. 그다지 아름답지는 않은 것으로 밝혀졌지만 안정적으로 작동합니다. 다운로드 페이지 에서 독립 실행형 버전을 찾아 압축을 풉니다. 그들만의 " 빠른 시작 "이 있습니다. 실행 후 주소가 나올 때까지 기다려야 합니다 http://127.0.0.1:8080/#repositorylist. 그런 다음 "아티팩트 업로드"를 선택하십시오.
IntelliJ 아이디어: 디컴파일, 컴파일, 대체(또는 다른 사람의 실수를 수정하는 방법) - 10
"업로드 시작"을 클릭한 다음 "파일 저장"을 클릭하세요. 그 후 녹색 성공 메시지가 나타나고 "찾아보기" 섹션에서 아티팩트를 사용할 수 있게 됩니다. jar 및 pom 파일에 대해 이 작업을 수행해야 합니다.
IntelliJ 아이디어: 디컴파일, 컴파일, 대체(또는 다른 사람의 실수를 수정하는 방법) - 11
이는 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라는 웹서버가 있습니다. 얼마 전까지 프록시를 사용할 때 최종 사용자의 IP를 알아낼 수 없는 버그가 있었습니다.
  • 당분간 WildFly JPA는 예외가 발생했기 때문에 사양에서 고려하지 않은 특정 방식으로 한 순간을 처리했습니다. 그리고 구성할 수 없었습니다.
#비아체슬라프
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION