일반적으로 자바 디컴파일러에 JAD 를 많이 사용하나, JAD 는 1.5 버젼부터는 잘 지원안된다.

그래서 보통 JD 를 많이 사용하는데, JD core 를 이용한 JD-Gui 를 이용하여 주로 사용한다.

허나, 이 또한 일부 디컴파일된 파일이 불안전할 수 가 있는데, 그 대안으로 cfr 을 추천한다.

cfr 또한 불안전한 파일이 나올 수 있으므로 본인은 JD-Gui 로 선행 작업 후, 컴파일 오류가 나는 것들에 대해서 cfr 로 디컴파일한 파일들을 사용한다. 

CFR

cfr 은 java 로 개발된 디컴파일로써, java8 의 람다와 java 7 의 switch 등을 지원한다.

http://www.benf.org/other/cfr/ 에서 최신 버젼을 내려 받은 후 다음과 같이 실행하면 된다. (문서 작성 당시에 cfr 버젼은 0.8.1 이었다.)

> java -jar cfr_0_81.jar <디컴파일할 jar 파일 경로> --outputdir <디컴파일된 소스 파일이 등록될 경로>

다음은 샘플이다.

D:\App\cfr>java -jar cfr_0_81.jar lnk.jar --outputdir d:/app/cfr/result

물론 이렇게 단순한 방법 말고도, 디컴파일시 소스 번호가 나오게 한다던지 등등 다양한 옵션이 존잰한다.

자세한 방법은 --help 를 쳐보면 된다 (웃음)

D:\App\cfr>java -jar cfr_0_81.jar --help
CFR 0_81
   --showops                        (int >= 0)  default: 0
   --decodeenumswitch               (boolean)  default: true if class file from
version 49.0 (Java 5) or greater
   --sugarenums                     (boolean)  default: true if class file from
version 49.0 (Java 5) or greater
   --decodestringswitch             (boolean)  default: true if class file from
version 51.0 (Java 7) or greater
   --arrayiter                      (boolean)  default: true if class file from
version 49.0 (Java 5) or greater
   --collectioniter                 (boolean)  default: true if class file from
version 49.0 (Java 5) or greater
   --innerclasses                   (boolean)  default: true
   --removeboilerplate              (boolean)  default: true
   --removeinnerclasssynthetics     (boolean)  default: true
   --decodelambdas                  (boolean)  default: true if class file from
version 52.0 (Java 8) or greater
   --hidebridgemethods              (boolean)  default: true
   --liftconstructorinit            (boolean)  default: true
   --removedeadmethods              (boolean)  default: true
   --removebadgenerics              (boolean)  default: true
   --sugarasserts                   (boolean)  default: true
   --sugarboxing                    (boolean)  default: true
   --showversion                    (boolean)  default: true
   --decodefinally                  (boolean)  default: true
   --tidymonitors                   (boolean)  default: true
   --lenient                        (boolean)  default: false
   --dumpclasspath                  (boolean)  default: false
   --comments                       (boolean)  default: true
   --forcetopsort                   (boolean)
   --forceexceptionprune            (boolean)
   --outputdir                      (string)
   --stringbuffer                   (boolean)  default: false if class file from
 version 49.0 (Java 5) or greater
   --stringbuilder                  (boolean)  default: true if class file from
version 49.0 (Java 5) or greater
   --silent                         (boolean)  default: false
   --recover                        (boolean)  default: true
   --eclipse                        (boolean)  default: true
   --override                       (boolean)  default: true if class file from
version 50.0 (Java 6) or greater
   --aexagg                         (boolean)
   --forcecondpropagate             (boolean)
   --hideutf                        (boolean)  default: true
   --hidelongstrings                (boolean)  default: false
   --commentmonitors                (boolean)  default: false
   --allowcorrecting                (boolean)  default: true
   --labelledblocks                 (boolean)  default: true
   --j14classobj                    (boolean)  default: false if class file from
 version 49.0 (Java 5) or greater
   --hidelangimports                (boolean)  default: true
   --recovertypeclash               (boolean)
   --forcereturningifs              (boolean)
   --help                           (string)

  

참조 : 다른 디컴파일러들에 대한 정보는 다음 링크에 잘 나와있다.

https://community.jboss.org/people/ozizka/blog/2014/05/06/java-decompilers-a-sad-situation-of

 유지보수 프로젝트에 들어가거나, 기존 업무 환경에서 작업해야할 경우 자신이 사용하고 있는 클래스가 위치한 위치를 찾고 싶은 경우가 있다.

다음과 같은 경우가 필요한 예일 것이다.

  • 실제 파일 위치를 확인 하기 위해서
  • NoSuchMethodError 가 날경우

 1. 실제 파일 위치를 찾기 위한 경우

해당 클래스가 위치한 실제 파일을 찾을 경우는 여러가지가 있다.

공통 jar 를 누군가가 배포해놓았는데, 교체를 해야하는데 어딨는지 도통 모르겠다거나,

그놈의 파일을 얻어다가 디컴파일 하고 싶은 욕구가 생길 경우가 그럴 경우다.

 2. NoSuchMethodError 가 날 경우

이 에러가는 나는 이유는 명백하다. 해당하는 클래스에 호출하는 메소드(메서드명과 인자가 일치하는) 가 없을 경우에 발생한다.

이 에러는 보통 다음과 같은 케이스에 발생하기 쉽다.

  • 런타임 환경에 배포를 안했을 때
  • 클래스 패스가 여러개 있어서, 우선순위가 높은 클래스패스에 이미 해당 클래스가 올려져 있을 때

런타임 환경에 배포를 안 했을 경우에는 참으로 기본적인 것이라 설명하는 것조차 무색하지만

후자의 경우에 많은 개발자들이 당황하기 쉽상이다.

즉, 다른 놈의 jar 안에 동일한명의 클래스가 올려져 있어서 이미 배포가 되어있는데 그것을 모르고 "배포했는데 왜 안되지? 왜 안되지?내렸다 올려도 안되네?"  하는 경우다.

하지만 프로그램은 참으로 정직하다.

대개 많은 개발자들이

내가 운영하고 있는 것도 아니고, 서버 구성도 모르는데 제가 어떻게 압니까?  나 몰라요 몰라

 할지 모르겠으나, 자바가 클래스 로드하는 개념만 분명히 알고 있다면 전혀 두려워 할 필요가 없을 거이다.

 

배포된 파일을 찾고자 할 경우에 해당하는 패키지명과 클래스는 개발자는 분명히 알고 있을것이다.

다음과 같이 작성하여 출력해보면 해당 위치를 찾을 수 있다.

 

java.net.URL r = this.getClass().getClassLoader().getResource("nts/toolkit/EnvelopedMessage.class");
System.out.println(r.toString());

 이 예는 nts.toolkit.EnvelopedMessage.class 가 어딨는지 출력하는 예이다. 이것을 출력하면 다음과 같은 출력을 볼 수 있다.

 

jar:file:/sys0.d/jeusdev2/jeus5/lib/application/NtsApi.jar!/nts/toolkit/EnvelopedMessage.class

 

이 말인 즉슨 jar 파일로 만들어져 있으며 jar 파일은 /sys0.d/jeusdev2/jeus5/lib/application/NtsApi.jar 이고 그 안에 nts.toolkit.EnvelopedMessage.class 가 있다는 뜻이다.

내가 안했다고 두려워하지 말길,,,

이 글은 스프링노트에서 작성되었습니다.

일반적으로 자바 실행시 사용되는 변수명으로 JAVA_OPTS 를 사용한다.
따라서 윈도우의 환경변수나, 리눅스의 프로필 파일에 JAVA_OPTS 를 등록하면 자바 실행시에 옵션을 지정할 수 있다.

대표적으로 사용되는 옵션을 정리해보았다.
-XX:PermSize=4m -XX:MaxPermSize=32m -Xms64m -Xmx128m -XX:+PrintGCDetails

-XX:+PrintGCDetails 는 GC 로그를 출력하는 옵션이다. GC LOG는 기본적으로 stdout 으로 출력되기 때문에 파이프라인 등을 통하여 파일로 기록하는편이 분석하기에 좋을것이다. 윈도우용은 어찌해야할지 모르겠다. 아는 사람은 코멘트를 달아주시길 바랍니다 (_  _)
  1. slothink 2009.08.17 18:14

    -XX:PermSize=32m -XX:MaxPermSize=128m -Xms128m -Xmx512m

1. 자바 SDK 를 다운받아 설치한다.(SDK : Standard Developer Kit, JDK: Java Developer Kit)
http://java.sun.com
J2EE는 엔터프라이즈용이다. EJB 등 J2EE 서버 개발 계획이 없다면, sdk로 설치한다.
설치경로는 임의대로 하되 디폴트 설치처럼 자바 버젼이 디렉토리명안에 들어가게 설치되는것을 권장한다.
ex) c:\j2sdk_1.4.12

2. 환경 변수를 설정한다.
예전 windwo 98이나, me 예선 command 창에서 set 명령어로 환경변수를 설정하는데, 윈도우 2000이나 xp 이상에선 시스템 화면에서 환경변수 창이 존재한다.
- 제어판 -> 시스템 -> 고급 -> 환경 변수로 이동한다.
- 환경변수에 아래 항목을 추가한다.
JAVA_HOME        C:\Program Files\J2SDK_1.5.11   (자바 SDK가 설치된 경로를 지정한다)
CLASS_PATH        .;%JAVA_HOME%\lib;               (현재 디렉토리와 자바의 기본라이브러리)
PATH                  %JAVA_HOME%\bin;                  (자바 실행 파일)

3. 제대로 되었는지 확인을 한다.
명령프롬프트(command.com or cmd.exe) 를 실행 시킨 후 프롬프트에

java -version

명령을 입력한다. 설치한 자바버젼이 올바르게 나온다면 정상적인 것이다.

- 알수 없는 명령이라고 나오면 path 변수에 자바설치경로\bin 디렉토리가 정확하게 설정되지 않은것이다.
- 설치한 버젼과 다른 버젼이 나온다면, 기존에 설치되어있던 자바 실행 경로가 우선순위가 높은 것이다. path에 등록된 항목을 살펴서, 앞쪽에 현재 설치한 sdk\bin 경로를 위치한다.

Seq Name Seq Name
\b backspace \f formfeed
\t horizontal tab \" double quote
\n newline \' single quote
\r carriage return \\ backslash
\### Latin encoded character \uHHHH Unicode encoded character
Calendar cal = Calendar.getInstance();
System.out.println("now:"+cal.getTime());
 
// Set date : 월은 0부터 시작된다
cal.set(year, month-1, day, hour, min, sec);

// Prev a year
cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) -1);
System.out.println("prev a year:"+cal.getTime());
 
 
// Prev a month
cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) -1);
System.out.println("prev a month:"+cal.getTime());
 
// Prev a week
cal.set(Calendar.HOUR, -1 * 24 * 7);
System.out.println("prev a week:"+cal.getTime());
 
// Prev a day
cal.set(Calendar.HOUR, -24);
System.out.println("prev a day:"+cal.getTime());

+ Recent posts