2013. 5. 22. 11:19


class Foo {
  public static void main(String args[]) {

    // s 라는 문자열 배열 선언과 초기화
    String s[] = { "Google", "Yahoo", "MSN", "땡칠이" };

    // 배열의 모든 요소 화면에 출력
    for (int i = 0; i < s.length; i++)
      System.out.println(s[i]);



/////////////////////////////////////////////////////////////////



    // 이렇게 하면 알아보기 쉽게 초기화할 수 있음
    String names[] = {  "맹구",
                      "배용준",
                      "땡칠이",
                      "장동건",
                      "강수정",
                      "송창식",
                      "황당해",
                      "고은아"};

   // 배열의 모든 요소 화면에 출력
   for (int i = 0; i < names.length; i++)
     System.out.println(names[i]);



/////////////////////////////////////////////////////////////////



    // new 연산자로, 10개의 문자열 오브젝트 미리 확보하기
    String cool[] = new String[10];
    for (int i = 0; i < cool.length; i++) {
      cool[i] = "ㅎㅎ"; // 모든 요소들을 "ㅎㅎ" 라는 문자열로 채우고
      System.out.format("%d = %s%n", i, cool[i]); // 출력하기
    }


  }
}

 

Posted by sungwonpekr
2013. 5. 22. 11:18

JNI(Java Native Interface)


플랫폼 독립성을 버리고, 기능을 취한다.
자바 프로그램을 작성하다보면, 부득이하게 시스템 의존적 코딩을 필요로 하는 때가 있다. 하지만, 자바로서는 그러한 욕구를 감당할 수는 없다. 따라서, 자바의 클래스 파일이 C/C++의 함수를 호출하여, 그 결과만 되돌려받게 하는 것도 한 방법이다. 그렇지만 이 자체로서 이미 플랫폼 독립적이라는 특성은 사라졌다고 볼 수밖에 없다.

프로그램 작성
첫째 단계, 자바 프로그램 작성
우선, Native접근이 필요한 메쏘드만 native 키워드를 사용해 구현하지 않은 채 그대로 두고, 나머지는 모두 구현한 후, 컴파일한다.

public class Hello
public native void getHello();

static {
System.loadLibrary("hello");
{}

public static void main(String[] args)
new Hello().getHello();
{}
}

javac Hello.java

public native void getHello() : getHello 함수가 native method라는 것을 의미한다.

static
System.loadLibrary("hello");
{}

이것은 공유 라이브러리를 실행시 로드하는 코드로 반드시 static 초기화에 포함되어야 한다. 이것은 플랫폼에 따라 다르게 행동하는데, 만일 Win32이면, hello.dll을, 솔라리스이면, libhello.so라는 이름의 라이브러리를 찾는다.

둘째 단계, C프로그램을 위한 헤더 파일 생성
javah와 -jni옵션을 이용하여, 헤더파일을 생성해 보자.

javah -jni Hello

생성된 헤더 파일 Hello.h는 다음과 같다.

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>

/* Header for class Hello */

#ifndef _Included_Hello
#define _Included_Hello
#ifdef __cplusplus
extern "C"
#endif


/*
* Class: Hello
* Method: getHello
* Signature: ()V
*/


JNIEXPORT void JNICALL Java_Hello_getHello
(JNIEnv *, jobject);

#ifdef __cplusplus
{}
#endif
#endif

여기서 생성된 함수 이름에 주목해 보자. '_'를 구분자로 크게 몇 부분으로 나뉘어져 있다.

Java : 항상 앞에 붙는다.
Hello : 클래스의 이름
getHello : 메쏘드의 이름
셋째 단계, 함수를 구현한다.
HelloImpl.c라는 이름으로 함수를 구현해 보자.

#include <jni.h>
#include "Hello.h"
#include <stdio.h>

JNIEXPORT void JNICALL Java_Hello_getHello(JNIEnv *env, jobject obj)

printf("OOPSLA\n");
return;
{}

넷째 단계, C파일을 컴파일하여, 공유 라이브러리를 생성한다.
이때, 비주얼 C++을 이용할 경우 다음과 같은 옵션을 준다.

cl /I본인의 자바 디렉토리)\include /I(본인의 자바 디렉토리)\include\win32 -LD HelloImp.c -Fehello.dll

솔라리스에서 컴파일할 경우 다음과 같은 옵션을 준다.

cc -G -I(자바 홈 디렉토리)/include -I(자바 홈 디렉토리)/include/solaris HelloImp.c -o libhello.so

마지막 단계, 프로그램을 실행한다.
java Hello

실행 결과:

OOPSLA

자바의 타입과 C++/C의 타입 매핑 문제
네이티브 메쏘드를 호출하는 것까지는 좋다. 하지만, 그 결과값이 있을 경우에는 타입의 괴리(Impedence)가 존재할 수밖에 없다. 따라서, jni.h에는 자바의 타입을 흉내낼 수 있는 여러 가지 타입을 정의해 놓았다.

Primitive Types
네이티브 메쏘드에서는 보통 자바의 타입 이름 앞에 j가 붙은 이름을 가진 타입을 사용함으로써, 마치 자바 프로그램을 작성하는 듯이 프로그램할 수 있다. 예를 들어, boolean은 jni.h에 jboolean이라는 이름의 타입과 매핑된다.

jboolean : 자바의 boolean(8비트) - typedef unsigned char jboolean
jbyte : 자바의 byte(8) - typedef signed char jbyte(WIN32의 경우이다. - System Dependent)
jchar : 자바의 char(16) - typedef unsigned short jchar
jshort : 자바의 short(16) - typedef short jshort
jint : 자바의 int(32) - typedef long jint(WIN32의 경우이다. - System Dependent)
jlong : 자바의 long(64) - typedef __int64 jlong(WIN32의 경우이다. - System Dependent)
jfloat : 자바의 float(32) - typedef float jfloat
jdouble : 자바의 double(64) - typedef double jdouble;
void : 자바의 void
위의 리스트에서, 오른쪽은 실제 jni.h가 이 타입들을 어떻게 정의하고 있는지를 보여 준다. 여기서, jbyte, jint, jlong은 시스템에 따라 적용할 타입이 변경될 소지가 있으므로, WIN32의 경우, 자바디렉토리\include\win32\jni_md.h에 정의되어 있다. 솔라리스인 경우에는 참고로 다음과 같다.

#ifdef _LP64 /* 64-bit Solaris */
typedef int jint;
#else
typedef long jint;
#endif
typedef long long jlong;
typedef signed char jbyte;

객체 타입
이 경우에도 비슷하다. 일반 객체는 jobject타입으로 통용하고, 나머지 특수한 클래스에 대해 매핑되는 타입을 두기로 한다.

jobject : 모든 자바 객체로 뒤에 나열된 모든 타입의 슈퍼 타입이다.
jstring : 자바의 java.lang.String클래스이다.
jclass : 자바의 java.lang.Class클래스이다.
jarray : 자바의 배열이다.
jthrowable ; 자바의 java.lang.Throwable 예외 사항이다.
배열
기타, 기본 타입의 배열을 위한 배열 타입도, 하나의 클래스로 정의되어 있다.

jbooleanArray;
jbyteArray;
jcharArray;
jshortArray;
jintArray;
jlongArray;
jfloatArray;
jdoubleArray;
jobjectArray;



함수와 메쏘드간의 인자 전달
문제는 jstring을 비롯한 타입들은 실제 printf문 같은 곳에서 직접 쓰일 수 없다는 것이다. 이것들은 다시, C/C++의 타입으로 변환되어 사용되어야 한다. 이것에 관한 여러 함수들이 JNIEnv라는 구조체에 정의되어 있다.

예를 들어, String객체를 C메쏘드에 넘기도록 앞의 Hello.java를 수정해 보자. 자바 소스는 단순히 선언을 바꾸는 것으로 끝난다.

public native void getHello(String name);

재컴파일과, javah를 이용해 만든 새로운 헤더 파일을 이용해 HelloImpl.c를 새로 작성해 보면,

JNIEXPORT void JNICALL Java_Hello_getHello(JNIEnv *env, jobject obj,jstring name)

char *str_name = (*env)->GetStringUTFChars(env, name, 0);
printf("Hello %s\n",str_name);
(*env)->ReleaseStringUTFChars(env, name, str_name);
return;
{}

이와 같이, JNIEnv의 멤버 함수로부터 도움을 받아야 한다.

이제 각 타입에 대해 인자 전달과 결과값 반환 방법을 알아 보자.

Primitive Types
기본 타입의 경우에는 다음과 같이 기존의 C/C++타입중 호환되는 타입의 재명명이므로, 그다지 인자 전달에 문제가 없다.

typedef unsigned char jboolean;
typedef unsigned short jchar;
typedef short jshort;
typedef float jfloat;
typedef double jdouble;

WIN32:
typedef long jint;
typedef __int64 jlong;
typedef signed char jbyte;

다만, boolean의 경우에는 true/false값이 다음과 같이 전달된다.

#define JNI_FALSE 0
#define JNI_TRUE 1

예를 들어, boolean타입의 인자를 주고, 반환받는 경우,

Hello.java:
Hello h = new Hello();
System.out.println("h.getBoolean(true) = "+h.getBoolean(true)); // 결과 : true

HelloImpl.c:
JNIEXPORT jboolean JNICALL Java_Hello_getBoolean(JNIEnv * env, jobject jobj, jboolean jbool)

......
return JNI_TRUE;
{}

배열 타입
각 기본 타입에 따라 그 배열을 다룰 수 있는 배열 클래스가 제공된다.

jarray
jbooleanArray
jbyteArray
jcharArray
jshortArray
jintArray
jlongArray
jfloatArray
jdoubleArray

모든 배열 클래스들은 jarray 클래스의 하위 클래스이다.

배열의 길이 파악
모든 배열의 길이를 알아낼 수 있는 함수는 다음과 같다.

jsize GetArrayLength(JNIEnv *, jarray array)

(jsize는 jint와 동일하다)

자바의 배열을 C의 배열로 변환하는 함수
각 타입마다 자바 타입의 배열을 C타입으로 변환시켜 주는 함수가 있다.

jboolean * GetBooleanArrayElements(JNIEnv *env,jbooleanArray array, jboolean *isCopy)
jbyte * GetByteArrayElements(JNIEnv *env,jbyteArray array, jboolean *isCopy)
jchar * GetCharArrayElements(JNIEnv *env,jcharArray array, jboolean *isCopy)
jshort * GetShortArrayElements(JNIEnv *env,jshortArray array, jboolean *isCopy)
jint * GetIntArrayElements(JNIEnv *env,jintArray array, jboolean *isCopy)
jlong * GetLongArrayElements(JNIEnv *env,jlongArray array, jboolean *isCopy)
jfloat * GetFloatArrayElements(JNIEnv *env,jfloatArray array, jboolean *isCopy)
jdouble * GetDoubleArrayElements(JNIEnv *env,jdoubleArray array, jboolean *isCopy)
정수의 경우를 예로 들어 보자.

jsize iSize = (*env)->GetArrayLength(env,jiarray);
jint *iArray = (*env)->GetIntArrayElements(env,jiarray,0);


for(i=0; i < iSize; i++)
printf("iArray[%d] = %d\n",i,iArray[i]);
iArray[i]++;
{}
(*env)->ReleaseIntArrayElements(env,jiarray,iArray, 0);

자바의 배열을 JNI에서 사용할 경우, 이것은 현재의 실행 루틴을 수행하는 쓰레드가 이 배열 객체에 대해 PIN 연산을 수행하거나, 아니면 전체의 로컬 복사본을 사용하게 되는 것이다. 이로 인해, 이 연산의 반대 급부로 반드시 UNPIN연산에 해당하는 ReleaseIntArrayElements가 불려지는 것이 좋다.

void ReleaseBooleanArrayElements(JNIEnv *env,jbooleanArray array, jboolean *elems, jint mode)
void ReleaseByteArrayElements(JNIEnv *env,jbyteArray array, jbyte *elems, jint mode)
void ReleaseCharArrayElements(JNIEnv *env,jcharArray array, jchar *elems, jint mode)
void ReleaseShortArrayElements(JNIEnv *env,jshortArray array, jshort *elems, jint mode)
void ReleaseIntArrayElements(JNIEnv *env,jintArray array, jint *elems, jint mode)
void ReleaseLongArrayElements(JNIEnv *env,jlongArray array, jlong *elems, jint mode)
void ReleaseFloatArrayElements(JNIEnv *env,jfloatArray array, jfloat *elems, jint mode)
void ReleaseDoubleArrayElements(JNIEnv *env,jdoubleArray array, jdouble *elems, jint mode)

이 외에도 다음과 같은 함수들이 있다.

jdoubleArray NewDoubleArray(jsize len)를 비롯해 각 기본 타입마다 새로운 자바 배열을 생성할 수 있다.
void GetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, jboolean *buf)를 비롯해 각 기본 타입마다 Sub배열을 획득할 수 있는 함수가 제공된다.


자바 객체의 사용
네이티브 코드 내에서 자바 객체를 사용할 수도 있다. 즉 콜백과 비슷한 형식을 지원한다. private영역까지 접근할 수 있다.

자바 객체의 클래스 정보 얻기
일단, 인자로 넘겨지는 자바 객체에 대한 클래스 정보를 획득하는 함수가 제공된다.

jclass cls = (*env)->GetObjectClass(env, jobj);

여기서 주의할 것은 반환값으로 돌아오는 cls의 레퍼런스값은 오직 이 네이티브 메쏘드가 수행이 끝날 동안에만 유효하다는 것이다.

자바 객체 및 클래스 타입의 래퍼런스는 네이티브 메쏘드 실행시마다 결정되므로, 한 번 실행해 얻은 레퍼런스를 다음번 메쏘드에서 다시 사용하려는 것은 잘못된 것이다.

따라서, 원칙적으로 객체 레퍼런스 변수를 전역 변수로 할당하는 것은 위험한 일이다. 하지만, 꼭 허용되지 않는 것은 아니다. 전역 레퍼런스로 지정해 줄 수 있는 함수가 있다.

jobject NewGlobalRef(JNI_Env* env, jobject lobj)





네이티브 코드를 호출한 객체의 메쏘드에 대한 ID얻기
객체의 메쏘드를 호출하기 위해 그 메쏘드의 ID를 획득해야 한다. 이것은 메쏘드의 이름과 시그너쳐를 이용하는데, 이름은 별 무리가 없겠으나, 시그너쳐는 까다롭다.

시그너쳐는 메쏘드의 인자 리스트와 반환 타입 정보를 스트링화한 것으로, 다음과 같은 규칙이 있다.

시그너쳐 : "(인자 리스트)반환값"으로 이루어진 스트링이다.
인자리스트의 인자들은 아래의 타입 기호에 따라 표기되며, 서로 ';'으로 구분된다.
반환값 역시 타입 기호에 따라 표시된다.
타입 기호는 다음과 같다. 이것은 자바 가상 머신 스펙에서 클래스 파일 포맷 부분에 등장하는 기호와 동일하다.

Z : boolean
B : byte
C : char
S : short
I : int
J : long
F : float
D : double

이들의 배열은 이들의 타입 기호 앞에 '['를 붙인다. 즉 int 배열은 [I가 된다.
클래스 타입의 경우, L뒤에 클래스명을 패키지명까지 포함해 나열하면 된다. 즉, String클래스인 경우, Ljava.lang.String이다.
이것은 수작업으로 할 경우, 실수가 많을 수 있으나, javap를 이용해, 쉽게 기호화된 시그너쳐를 확인할 수 있다.

javap -s -p Hello

Compiled from Hello.java
class Hello extends java.lang.Object
static {{};
/* ()V */
Hello();
/* ()V */
public static void coo(java.lang.String, java.lang.String);
/* (Ljava/lang/String;Ljava/lang/String;)V */
private void foo(java.lang.String, java.lang.String);
/* (Ljava/lang/String;Ljava/lang/String;)V */
public native boolean getBoolean(boolean);
/* (Z)Z */
public native byte getByte(byte);
/* (B)B */
public native char getChar(char);
/* (C)C */
public native double getDouble(double);
/* (D)D */
public native float getFloat(float);
/* (F)F */
public native java.lang.String getHello(java.lang.String);
/* (Ljava/lang/String;)Ljava/lang/String; */
public native int getInt(int);
/* (I)I */
public native int getIntArray(int[])[];
/* ([I)[I */
public native long getLong(long);
/* (J)J */
public native short getShort(short);
/* (S)S */
public static void main(java.lang.String[]);
/* ([Ljava/lang/String;)V */
}

이것은 다음과 같이 Hello클래스에 두 메쏘드를 추가한 후의 javap결과이다.

private void foo(String str,String str1)
System.out.println("Hello.foo() = "+str+str1);
{}

public static void coo(String str,String str1)
System.out.println("Hello.coo() = "+str+str1);
{}

이제 foo메쏘드의 ID를 획득해 보자.

// 클래스 정보 획득
jclass cls = (*env)->GetObjectClass(env, obj);

// 메쏘드 ID
jmethodID fooM = (*env)->GetMethodID(env, cls, "foo", "(Ljava/lang/String;Ljava/lang/String;)V");

// 그런 메쏘드가 없으면, 0반환
if(fooM == 0)
printf("Method foo isn't found\n");
{}
else
......
{}



인자 생성 및 메쏘드 호출
이제 메쏘드를 호출하는 일이 다음 순서가 되겠다. 물론 여기에 해당되는 함수들이 제공되는데, 이 함수들을 통해, 클래스 내의 메쏘드를 호출하므로, 메쏘드 ID와 더불어 메쏘드의 인자들을 리스트화해서 보내야 한다. 두 가지 방법이 있다.

C의 va_list구조체를 이용한다.
jvalue 유니온를 이용한다.
여기서는 jvalue 유니온을 이용해 보자. 그 구조는 다음과 같다.

typedef union jvalue
jboolean z;
jbyte b;
jchar c;
jshort s;
jint i;
jlong j;
jfloat f;
jdouble d;
jobject l;
{} jvalue;

그러면, 스트링 두 개를 인자로 받는 foo메쏘드를 호출해 보자. String은 객체이므로, l에 스트링 객체의 레퍼런스를 할당하면 된다.

jvalue* args;
.......

args = (jvalue*)malloc(sizeof(jvalue)*2);
args[0].l = (*env)->NewStringUTF(env,"oops");
args[1].l = (*env)->NewStringUTF(env,"la");
(*env)->CallVoidMethodA(env, obj, fooM,args ); // JNIEnv, jobject, Method ID, jvalue

여기에서는 foo가 void 타입이므로, CallVoidMethodA가 쓰였지만, 이 외에에도 반환값에 따라 여러 함수가 제공된다. 이들의 인자는 위와 동일하다.

jboolean CallBooleanMethodA
jbyte CallByteMethodA
jchar CallCharMethodA
jshort CallShortMethodA
jint CallIntMethodA
jfloat CallFloatMethodA
jdouble CallDoubleMethodA
참고로, va_list를 이용하여 인자를 전달하는 함수들은 A로 끝나지 않고, V로 끝나는데, 역시 마지막 인자만 va_list타입으로 수정해 주면 된다.



정적 메쏘드 호출
정적 메쏘드 또한 호출할 수 있는 함수가 따로 있다.

메쏘드 ID : GetStaticMethodID함수 이용
jMethodID cooM = (*env)->GetStaticMethodID(env, cls, "coo", "(Ljava/lang/String;Ljava/lang/String;)V");
if(cooM == 0)
printf("Method foo isn't found\n");
{}
else .....
{}

인자 형성 방법은 동일하다.
메쏘드 호출 : CallStaticVoidMethodA 이용
cooM = (*env)->GetStaticMethodID(env, cls, "coo", "(Ljava/lang/String;Ljava/lang/String;)V");
if(cooM == 0)
printf("Method foo isn't found\n");
{}
else
args = (jvalue*)malloc(sizeof(jvalue)*2);
args[0].l = (*env)->NewStringUTF(env,"papa");
args[1].l = (*env)->NewStringUTF(env,"ya");
(*env)->CallStaticVoidMethodA(env, cls, cooM,args );
{}

여기서 주의할 것은 CallStaticVoidMethodA의 두 번째 인자는 jobject타입이 아닌, jclass타입이란 것이다. 클래스 메쏘드이니 당연하기도 하다.



상위 클래스의 메쏘드 호출
한 걸음 더 나아가 상위 클래스의 메쏘드도 호출할 수 있다. 여기에 해당되는 메쏘드는 모두 NonVirtual이라는 이름을 포함하고 있는데, c++을 배운 이라면, NonVirtual의 의미를 알고 있을 것이다.

상위 클래스 타입의 jclass 객체 획득
jclass sClass = (*env)->GetSuperclass(env,cls);

메쏘드 ID : GetMethodID함수 이용
superFooM = (*env)->GetMethodID(env, sClass, "foo", "(Ljava/lang/String;Ljava/lang/String;)V");
if(superFooM == 0)
printf("Method foo isn't found\n");
{}
else
.....
{}

메쏘드를 호출: CallNonvirtualVoidMethodA
args = (jvalue*)malloc(sizeof(jvalue)*2);
args[0].l = (*env)->NewStringUTF(env,"can");
args[1].l = (*env)->NewStringUTF(env,"dy");
(*env)->CallNonvirtualVoidMethodA(env,obj,sClass ,superFooM,args );


멤버 필드 접근
필드를 접근하는 방법 또한 메쏘드를 접근하는 방법과 크게 다르지 않다. 필드가 Private일지라도 접근할 수 있다. 이 또한 몇 가지 함수에 의존하고 있는데, 그 함수의 형식이 메쏘드를 호출하는 함수와 거의 유사하기 때문이다. 일단 다음의 기호를 잊지 말자.

Z : boolean
B : byte
C : char
S : short
I : int
J : long
F : float
D : double

이들의 배열은 이들의 타입 기호 앞에 '['를 붙인다. 즉 int 배열은 [I가 된다.
클래스 타입의 경우, L뒤에 클래스명을 패키지명까지 포함해 나열하면 된다. 즉, String클래스인 경우, Ljava.lang.String이다.
이제 Hello.java에 몇 가지 필드를 추가해 보자.

private int intVal;
private static int iStaticIntVal;
private String strVal = "Hello";

이를 재컴파일 후, javah를 실행하고, 새로이 생긴 함수의 선언부를 HelloImpl.c로 복사해 이것에 대해 추가적으로 구현해 보기로 하자.

필드를 접근하는 것은 두 단계로 이루어진다.

클래스와 필드의 이름과 타입을 이용해 필드의 ID를 얻어낸다.
필드의 ID와 객체를 이용해 실제 필드의 값을 얻어낸다.
인스턴스 필드 접근
먼저 필드의 ID를 얻어내기 위한 함수는 다음과 같다.

jfieldID GetFieldID(JNI_Env* env,jclass clazz, const char *name, const char *sig)


그리고, 인스턴스 필드를 접근하는 함수들은 다음과 같다.

1) Read 함수
jobject GetObjectField(JNI_Env* env,jobject obj, jfieldID fieldID)
jboolean GetBooleanField(JNI_Env* env,jobject obj, jfieldID fieldID)
jbyte GetByteField(JNI_Env* env,jobject obj, jfieldID fieldID)
jchar GetCharField(JNI_Env* env,jobject obj, jfieldID fieldID)

jshort GetShortField(JNI_Env* env,jobject obj, jfieldID fieldID)
jint GetIntField(JNI_Env* env,jobject obj, jfieldID fieldID)
jlong GetLongField(JNI_Env* env,jobject obj, jfieldID fieldID)
jfloat GetFloatField(JNI_Env* env,jobject obj, jfieldID fieldID)
jdouble GetDoubleField(JNI_Env* env,jobject obj, jfieldID fieldID)
2) Write 함수
void SetObjectField(JNI_Env* env,jobject obj, jfieldID fieldID, jobject val)
void SetBooleanField(JNI_Env* env,jobject obj, jfieldID fieldID, jboolean val)
void SetByteField(JNI_Env* env,jobject obj, jfieldID fieldID,jbyte val)
void SetCharField(JNI_Env* env,jobject obj, jfieldID fieldID, jchar val)
void SetShortField(JNI_Env* env,jobject obj, jfieldID fieldID,jshort val)
void SetIntField(JNI_Env* env,jobject obj, jfieldID fieldID,jint val)
void SetLongField(JNI_Env* env,jobject obj, jfieldID fieldID, jlong val)
void SetFloatField(JNI_Env* env,jobject obj, jfieldID fieldID, jfloat val)
void SetDoubleField(JNI_Env* env,jobject obj, jfieldID fieldID, jdouble val)


클래스 필드 접근
Static 필드를 접근하기 위해 먼저 ID를 얻어내야 한다.

jfieldID GetStaticFieldID(JNI_Env* env,jclass clazz, const char *name, const char *sig)

그리고, 필드를 접근하는 함수들은 다음과 같다.

Gettor 함수
jobject GetStaticObjectField(JNI_Env* env,jclass clazz, jfieldID fieldID)
jboolean GetStaticBooleanField(JNI_Env* env,jclass clazz, jfieldID fieldID)
jbyte GetStaticByteField(JNI_Env* env,jclass clazz, jfieldID fieldID)
jchar GetStaticCharField(JNI_Env* env,jclass clazz, jfieldID fieldID)
jshort GetStaticShortField(JNI_Env* env,jclass clazz, jfieldID fieldID)
jint GetStaticIntField(JNI_Env* env,jclass clazz, jfieldID fieldID)
jlong GetStaticLongField(JNI_Env* env,jclass clazz, jfieldID fieldID)
jfloat GetStaticFloatField(JNI_Env* env,jclass clazz, jfieldID fieldID)
jdouble GetStaticDoubleField(JNI_Env* env,jclass clazz, jfieldID fieldID)
Settor 함수
void SetStaticObjectField(JNI_Env* env,jclass clazz, jfieldID fieldID, jobject value)
void SetStaticBooleanField(JNI_Env* env,jclass clazz, jfieldID fieldID, jint value)
void SetStaticByteField(JNI_Env* env,jclass clazz, jfieldID fieldID, jbyte value)
void SetStaticCharField(JNI_Env* env,jclass clazz, jfieldID fieldID, jchar value)
void SetStaticShortField(JNI_Env* env,jclass clazz, jfieldID fieldID, jshort value)
void SetStaticIntField(JNI_Env* env,jclass clazz, jfieldID fieldID, jint value)
void SetStaticLongField(JNI_Env* env,jclass clazz, jfieldID fieldID, jlong value)
void SetStaticFloatField(JNI_Env* env,jclass clazz, jfieldID fieldID, jfloat value)
void SetStaticDoubleField(JNI_Env* env,jclass clazz, jfieldID fieldID, jdouble value)
예제
이제 이들을 사용해 Hello 클래스의 필드들을 접근해 보기로 하자. Hello.java에 native메쏘드인 다음을 추가하고 컴파일 후, HelloImpl.c에서, 다음을 중심으로 코딩해 보자.

public native void testFieldAccess()

정적 변수 접근
정적 필드인 iStaticIntVal 필드를 접근하여, 값을 읽어들인 후, 다시 2를 더해 값을 써 보자.

jfieldID jFieldId;
jint iStaticIntVal;
jclass cls = (*env)->GetObjectClass(env, jobj);

jFieldId = (*env)->GetStaticFieldID(env,cls,"iStaticIntVal","I");
if(jFieldId == 0)
printf("Field iStaticIntVal not Found in Hello class\n");
return;
{}

// 값을 읽어들인 후,
iStaticIntVal = (*env)->GetStaticIntField(env,cls,jFieldId);

// 2를 더해, 다시 그 값을 쓴다.
(*env)->SetStaticIntField(env,cls,jFieldId,(iStaticIntVal+2));

인스턴스 변수 접근
jint iVal;
jfieldID jFieldId;
jclass cls = (*env)->GetObjectClass(env, jobj);
jFieldId = (*env)->GetFieldID(env,cls,"intVal","I");
if(jFieldId == 0)
printf("Field intVal not Found in Hello class\n");
return;
{}
iVal = (*env)->GetIntField(env,jobj,jFieldId);
printf("iVal in C = %d\n",iVal);
(*env)->SetIntField(env,jobj,jFieldId,iVal);

그런데, 실제로 int를 가지고 실험해 본 결과, C에서 값을 잘 넘겨받는 것까지는 좋은데, 다시 자바로 값을 써 줄 때, 인자가 잘 전달되지 않는 현상을 보였다. 좀더 생각해 볼 문제이다.

스트링 접근
스트링은 객체이므로 객체를 접근하는 방식을 통해 접근해야 한다. 우선 GetFieldID 함수의 인자로 "Ljava/lang/String;"을 주목하면, 객체의 접근 방식과 동일함을 알 수 있다. 여기에서 세미콜론(;)을 빠뜨리면, 인식하지 못하므로 주의하기 바란다.

jstring jstr;
jfieldID jFieldId;
jclass cls = (*env)->GetObjectClass(env, jobj);

jFieldId = (*env)->GetFieldID(env,cls,"strVal","Ljava/lang/String;");
if(jFieldId == 0)
printf("Field strVal not Found in Hello class\n");
return;
{}

jstr = (*env)->GetObjectField(env,jobj,jFieldId);
(*env)->SetStaticIntField(env,cls,jFieldId,(iStaticIntVal+2));
str = (*env)->GetStringUTFChars(env, jstr, 0);
printf("Get String : %s\n",str);


새로운 스트링을 생성하여, 이것의 레퍼런스값을 str 필드에 할당하려면, 다음과 같이 한다.
jstr = (*env)->NewStringUTF(env, "123");
(*env)->SetObjectField(env, jobj, jFieldId, jstr);

기타 객체를 호출하는 방법도 스트링과 거의 동일하다. (*env)->GetObjectField(env,jobj,jFieldId);를 통해, jobject타입의 객체를 얻어낸 후, 필요에 따라 이 객체의 메쏘드를 호출하면 된다.



예외 사항
예외 사항 던지기
이제 예외 사항을 던지는 방법을 알아보자. 예외 사항들은 각각 클래스로 되어 있으므로, 이들의 클래스 정보를 얻어낸 후, 다음의 함수를 이용하면 된다.

jint ThrowNew(JNI_Env* env, jclass clazz, const char *msg)


Hello.java에서 testFieldAccess가 java.io.IOException을 던지도록 수정해 보자.

public native void testFieldAccess() throws java.io.IOException;

javac Hello.java
javah -jni Hello

이제 새로이 HelloImpl.c에서, testFieldAccess의 끝에 다음을 추가해 보자.

jclass eCls;

eCls = (*env)->FindClass(env, "java/io/IOException");
if(eCls != 0)
(*env)->ThrowNew(env, eCls, "IOException from C");
{}

예외 사항 감지하기
JNI의 C코드에서, 자바의 메쏘드를 호출했을 때.예외 사항이 돌아올 수 있다. 이 때, 감지하는 데 사용되는 함수는 다음과 같다.

jthrowable ExceptionOccurred(JNIEnv* env)

이것은 jthrowable타입의 예외 사항 객체를 반환해 준다. 그 예외 사항에 정보를 출력하는 데 사용되는 함수도 제공된다.

void ExceptionDescribe(JNI_Env* env)

그리고, 예외 사항이 처리된 후, 다시 예외 사항이 없는 것처럼 하려면, 다음과 같은 함수를 수행한다.

void ExceptionClear(JNI_Env* env);

이제 Hello.java에 새로운 메쏘드를 추가해 보자.

public void returnException() throws java.io.IOException
throw new java.io.IOException("IOException from Java");
{}

이 메쏘드를 C에서 호출하면, 예외 사항이 그쪽으로 반환될 것이다. 이것을 처리하는 코드는 다음과 같다.

jmethodID jmId;
jthrowable jexcp;

jmId = (*env)->GetMethodID(env,cls,"returnException","()V");
if(jmId == 0)
printf("Method returnException not found\n");
{}
else
(*env)->CallVoidMethod(env,jobj,jmId);
jexcp = (*env)->ExceptionOccurred(env);
if(jexcp) {
(*env)->ExceptionDescribe(env); // 예외 사항 정보 출력
(*env)->ExceptionClear(env);
{}
}

가비지 콜렉션
강제 레퍼런스 해제
원래 네이티브 메쏘드 내의 로컬 변수들이나 전역 변수들이 각각 지니고 있는 자바 객체에 대한 레퍼런스는 네이티브 메쏘드가 끝난 후에야 비로소 없어진다. 따라서, 네이티브 메쏘드가 오랜 시간동안 수행될 경우, 초반에만 실질적으로 사용될 뿐, 후반부에서는 쓰이지 않는 객체의 레퍼런스조차 메쏘드 전체가 수행이 끝날 때까지 남아있게 되는 셈이다. 이때 강제로 레퍼런스를 무효화시킬 수 있는 방법이 있다. 다음의 함수를 사용하면 된다.

void DeleteLocalRef(JNI_Env* env,jobject obj) // 지역 변수
void DeleteGlobalRef(JNI_Env* env,jobject gref) // 전역 변수


동기화
synchronized블록과 같은 동기화 블록을 C 코드내에서 지정해야 할 때가 있다. 바로 쓰레드에 의해 네이티브 메쏘드가 호출되었을 때, 이 메쏘드가 공유 변수들을 접근할 수 있기 때문이다. 그러한 용도로 사용되는 함수는 다음과 같다.

(*env)->MonitorEnter(JNI_Env* env,jobject obj);
(*env)->MonitorExit(JNI_Env* env, jobject obj);
이 두 메쏘드 사이에 있는 코드들은 쓰레드들간에 동기화된다.

 

출처 : http://www.mobilejava.co.kr/bbs/view.jsp?id=189&code=lecboard

Posted by sungwonpekr
2013. 5. 22. 11:12

  • Request code
  1.  
  2. TransformationInput in; // input payload
  3.  
  4. String msgID = in.getInputHeader().getMessageId();

    getTrace().addWarning("msgID : " + msgID);

  5.  
  6. // 전달할 데이터 
  7. String data = ""; 
  8.  
  9. // set to dynamic config:
  10. DynamicConfiguration conf = in.getDynamicConfiguration();
  11. DynamicConfigurationKey key = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/SOAP", msgID);
  12. if (conf != null) {
  13. conf.put(key, data);
  14. }

 

 

  • Response code

  1. TransformationInput in;

     

    String data = "";

     

    String reqMsgID = in.getInputHeader().getRefToMessageId();


    // set to dynamic config:

    DynamicConfiguration conf = in.getDynamicConfiguration();

    DynamicConfigurationKey key = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/SOAP", reqMsgID);

     

    if (conf != null) {

    data = conf.get(key);

    }

     

 

 

Posted by sungwonpekr
2013. 5. 22. 11:11

async parameter

QualityOfService=ExactlyOnce


참조 링크

http://help.sap.com/saphelp_nw04/helpdata/en/bf/27fd3b651f6a1ce10000000a11402f/frameset.htm

Posted by sungwonpekr
2013. 5. 22. 11:08


 필요 Library :

 

sapjco3-NTintel-3.0.6.zip


 

( OS와 CPU에 따른 Library 선택 필요)

 

 

 

 JCO를 이용한 Server :

 

jcoServerSample.jar


 

 

 

 JCO를 이용한 client :

 

jcoClientSample.jar


 

 

 (sample이 어려운데 나중에 다시 정리 해야겠다.)

 

 

 




Posted by sungwonpekr
2013. 5. 22. 10:57

자바매핑 SDN 가이드 페이지



 자바 매핑 샘플 : 


http2XML.java


 

 

 필요 Library : 

 

com.sap.xi.mapping.tool.lib_api.jar


com.sap.xpi.ib.mapping.lib.jar




Posted by sungwonpekr
2013. 5. 22. 10:44




 

  1. // set to dynamic config:
  2. DynamicConfiguration conf = in.getDynamicConfiguration();
  3. DynamicConfigurationKey idkey = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/HTTP", "UrlParamOne");
  4. DynamicConfigurationKey SVCIDkey = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/HTTP", "UrlParamTwo");
  5. DynamicConfigurationKey Kkey = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/HTTP", "UrlParamThree");
  6.  
  7. if (conf != null) {
  8. conf.put(idkey, ID);
  9. conf.put(SVCIDkey, SVCID);
  10. conf.put(Kkey, KEY);
  11. }

 

참고 : http://www.sdn.sap.com/irj/scn/weblogs?blog=/pub/wlg/7264



Posted by sungwonpekr
2013. 5. 22. 10:40


 

 SAP

System No. : 00 

 

 

 

 

 

RFC  -> 

GUI   -> 

 Message Server

Port : 3600 

 

 Gateway

Port : 3300 

 

 Application Server

Port : 3200 

 
    
    
 

 XI System No. : 00

 Port : 50000 

        5 : 고정값

중간 00 : System No. 

   끝 00 : 고정값

  XI System No. : 10

 Port : 51000 

    




Posted by sungwonpekr
2013. 5. 22. 10:28

## 공통 ##

 

  • Ctrl + /      : 커맨드로 포커스 넘어감
  • /n[code]   : 커맨드에 입력시 바로 넘어감
  • SU01         : 계정 정보


 

## XI ##

  • SXMB_MONI  : 모니터링
  • STMS (Transport Management System)  : CTS+ 이관
  • SE01 (Transport Organizer) : 이관관련
  • sxmb_adm  : xi/pi  세팅 메뉴

     

 

 

## ECC ##

  • smq2   : qRFC Monitor (Inbound Queue) proxy -> queue에서 queue에서 막힐경우 확인/재처리
  • se11    :  ABAP Dictionary   모든 Data Definition을 관리할 수 있다.
  • se16    : Data Browser  조회하고자 하는 Table명을 입력하고 실행하면 데이터를 적절한 조건에 맞게 조회할 수 있는 Selection Screen이 나타난다.
  • se37   : Function Builder   프로그램시 함수와 동일, 이를 생성하고 변경할 수 있는 TOOL
  • ST22    :  SAP 오류 로그
  • SXI_MONITOR  : 모니터링
  • SM59    :  TCP/IP 확인




    --BC관련(시스템 퍼포먼스 모니터링 및 분석)
    SM21 시스템온라인 로그 분석 (R/3에서 발생한 작업에 대한 로그분석)
    SM37 배치작업 조회
    SM36 배치작업 생성
    SM50 (현재 로그인해서 들어와 있는 시스템내 전체 작업에 대한 모니터링)
    SM66(R/3전체 시스템내 현재 돌고 있는 작업들에 대한 모니터링)
    ST11 개발자 추적조회
    ST22 (ABAP 덤프 로그 분석)
    DB01 (배타적 잠금 대기 분석-DB lock 잡고 있는것에 대한 분석)
    SMGW (gateway monitor)
    ST05 (성능 추적)
    SEARCH_SAP_MENU
    (SAP메뉴에서 찾기-->찾고자하는 TCODE를 한글로 내용 입력하면 유사한 TCODE를 찾아줌)
    ABAPDOCU (ABAP 예제로 직행)
    SE30 (ABAP OBJECT RUNTIME ANALYSIS)
     
     
     
    SE01 - 툴 -> 관리 -> 운송 -> 전송 Organizer
    SE11 - 툴 -> ABAP Workbench -> 개발 -> ABAP Dictionary
    SE16 - 툴 -> ABAP Workbench -> 개요 -> 데이타브라우저
    SE30 - 툴 -> ABAP Workbench -> 테스트 -> 실행시간분석
    SE32 - 툴 -> ABAP Workbench -> 개발 -> 프로그래밍환경 -> 텍스트요소
    SE37 - 툴 -> ABAP Workbench -> 개발 -> Function 작성기
    SE38 - 툴 -> ABAP Workbench -> 개발 -> ABAP편집기 (Include 수정)
    SE39 - 툴 -> ABAP Workbench -> 개발 -> 프로그래밍환경 -> 분할화면편집기
    SE43 - 툴 -> ABAP Workbench -> 개발 -> 기타툴 -> 영역메뉴
    SE80 - 툴 -> ABAP Workbench -> 개요 -> 오브젝트 네비게이터
    SE81 - 툴 -> ABAP Workbench -> 개요 -> 어플리케이션 계층구조
    SE91 - 툴 -> ABAP Workbench -> 개발 -> 프로그래밍환경 -> 메세지
    SE93 - 툴 -> ABAP Workbench -> 개발 -> 기타툴 -> 트랜잭션
     
    SQVI - 툴 -> ABAP Workbench -> 유틸리티 -> 퀵뷰어
    SQ01 - 툴 -> ABAP Workbench -> 유틸리티 -> SAP질의 -> 질의
    SQ02 - 툴 -> ABAP Workbench -> 유틸리티 -> SAP질의 -> 인포세트
    SQ03 - 툴 -> ABAP Workbench -> 유틸리티 -> SAP질의 -> 사용자그룹
    SQ07 - 툴 -> ABAP Workbench -> 유틸리티 -> 환산 -> ABAP 질의
     
    SM01 - 툴 -> 관리 -> 관리 -> 트랜잭션코드관리
    SM02 - 툴 -> 관리 -> 관리 -> 시스템메세지
    SM04 - 툴 -> 관리 -> 모니터 -> 시스템 모니터링 -> 사용자개요 / SESSION 끊기
    SM12 - 툴 -> 관리 -> 모니터 -> 잠금엔트리
    SM13 - 툴 -> 관리 -> 모니터 -> 갱신
    SM50 - 툴 -> 관리 -> 모니터 -> 시스템 모니터링 -> 프로세스 개요
    SM58 - 툴 -> 관리 -> 모니터 -> 트랜잭션 RFC
    SM59 - 툴 -> 관리 -> 관리 -> 네트웍 -> RFC 목적지
     
    SU01 - 사용자 정보관리(비번, 날짜포멧 등등 ) 
     
    ST05 - 툴 -> ABAP Workbench -> 테스트 -> SQL 추적
    ST22 - 툴 -> 관리 -> 모니터 -> 덤프분석 
     
    SPAU - 유틸리티 -> 유지보수 -> 업그레이드 유틸리티 -> 프로그램비교
    SHD0 - 툴 -> ASAP -> Personalization -> Transaction Variants
    SCC1 - 툴 -> 관리 -> 관리 -> 클라이언트관리 -> 특별 Function -> 전송요청
    SMARTFORMS - 툴 -> 서식인쇄출력 -> Smart Forms
    STMS - 툴 -> 관리 -> 운송 -> 전송관리시스템
     
     
    **************************************************************************************************
    SD 관련
    **************************************************************************************************
    VA01 : 판매오더생성 (VBAK - VBAP TABLE 및 기타 정보)
    VA02 : 판매오더변경 (VBAK - VBAP TABLE 및 기타 정보)
    VA03 : 판매오더조회 (VBAK - VBAP TABLE 및 기타 정보)
     
    VL01 : 아웃바운드 납품문서 생성 (LIKP - LAPS)
    VL02 : 아웃바운드 납품문서 변경 (LIKP - LAPS)
    VL03 : 아웃바운드 납품문서 조회 (LIKP - LAPS)
     
    VF01 : BILLING 생성
    VF02 : BILLING 변경
    VF03 : BILLING 조회
     
    VK11 : 국내고객 가격생성
    XD01 : 거래처 생성(MM)
    VD01 : 고객 생성(SD)
     
    SE54 : 유지보수 VIEW 생성

Posted by sungwonpekr
2013. 5. 22. 10:24

1) 코딩을 할 때 라인 번호가 있어야 편하다.
워크벤치-에디터-텍스트 에디터-쇼라인넘버즈
어플라이 하면 된다.
 
2) 코드 스타일 바꾸기Windows > Prefrences >
Java > Code Style > Formatter
하나를 만들어서 그거 이용하도록
에디터에서 적용방법 : Ctrl + Shift + F 또는 Source > Format
특 정부분만 적용하려면 블록 후 Ctrl + Shift + F
 
3) 퍼스펙티스 설정 저장
WIndow > Save Perspective As
 

(4) 코드 어시스트 Ctrl + Space
for, while 자동완성
sysout 자동완성
템플릿 설정은 Preferences
Java > Editor > Templates
Actio 정도만 치고 Ctrl+Space를 치면 적당한 후보를 내줍니다.
요것도 여러번 연습해서 습관이 되도록 하셔야겠지요.
for(int i = 0; i < array.length; i++)
이거 치기 참 힘드시죠?
for만 치시고 ctrl+space 누르시면
슈루룩 완성이 됩니다.
중간에 바꿔야 할건 tab키를 이용하면 바꿀 수 있고요.
 
(5) Quick fix
에러난 줄에 노란전구가 있으면 Ctrl + 1 눌러서 방법중 하나 고르면 수정된다.
빨간 줄이 보이세요? 커서를 올려놓고 기다려보세요.
올려놓고 기다리시면 왜 빨간줄이 나왔는지 나옵니다.
도대체 어떻게 고쳐야할지 모르겠다 싶으시면
한번 Ctrl+1을 눌러보세요. 알아서 고쳐줄지도 모릅니다.
(안고쳐줄때도 많긴 합니다만, 편할때도 많습니다^^)

(6) Quick Type Hierarchy
메서드, 타입, 패키지를 선택하고 Ctrl + T
한번 더 누르면 뒤집어짐

(7) Quick Outline
Ctrl + 0 키를 누르면 바로 필터링됨

(8) 소스 코드 네비게이션정의로 바로가기 : F3
다시 돌아오기 : Alt + <- , 다시 정의보기 : Alt + ->
Ctrl 누르고 있으면 각 요소가 하이퍼링크 모양으로 바뀜 : 이때 마우스 클릭시 이동
해당라인 이동 : Ctrl + L
 
(9) Mark Occurences
툴 바버튼이 눌려있으면 커서가 위치한 요소는 사용처가 다 보임

(10) getter, setter, 생성자
소스에서 Source > 해서 선택

(11) 소스비교
우클릭 > Compare with > Local History
Replace With > Local History
Restore from Local HIstory

(12) 에디터간 이동
많아지면 오른쪽 >> 클릭
Ctrl + F6 :
 
(13) 뷰 간 이동Ctrl + F7

(14) 퍼스펙티브간 이동
Ctrl + F8

(15) 에디터로 돌아오기
어디에 있든 F12
 
(16) 찾기
점 증적찾기 : Ctrl + J (아래에 Incremental File표시)
그리고 단어입력
그리고 Ctrl + J 클릭시 다음단어 찾음 (Ctrl + Shift + J는 반대)
블록선택후 Ctrl + K 클릭시 다음단어
검색기능
일 반 검색 : Ctrl + F
마우스로 드레그한 항목 아래로 검색 : Ctrl + K
마우스로 드레그한 항목 위로 검색 : Ctrl + Shift + K
실시간 타이핑 검색 (아래로) : Ctrl + J
실시간 타이핑 검색 (위로) : Ctrl + Shift + J

(17)  소스편집
원하는 라인으로 이동 : Ctrl + L
한 라인 삭제 : Ctrl + D
주석처리 : Ctrl + Shift + /     --->   형태 : /*  */
                Ctrl + /    ----> 형태 : //
자동 들여쓰기 정리 : Ctrl + I
자동으로 임포트하기 : Ctrl + Shift + O
소스창 전체화면 전환 : Ctrl + M
System.out.println(); 간단하게 입력하기 : sysout 입력 후 Ctrl + Space
try { } catch { } 간단하게 입력하기 : try 입력 후 Ctrl + Space
for문 간단하게 입력하기 : for 입력 후 Ctrl + Space
열린파일 이동할때 리스트 항목을 보고 선택하기 : Ctrl + F6
Ctrl  +  Shift  +  O  -  Organize  Imports
저장전에는  필히  import  구문을  정리  해주시고..
Ctrl  +  Shift  +  F  -  Reformat  source
저장전  소스  들여쓰기도  자동으로  정리해주시고
Alt  +  Shift  +  J  -  Java  Doc  Comment  Create
아직도  Java  Doc을  안다는가..  달어줘라  개발자의  센스다.  일일히  타이핑  하는가..
이젠  이단축키  하나로..  메소드나  클래스  명에  위치시키고  눌러봐라.  파라미터,  throws를  분석하여  친절하게  Doc주석을  달어준다.
--------------------------------------------------------------------------------
1. 옮길 문장이 있는 줄을 아무데나 클릭한다.
2. Alt키와 화살표(위로)키를 누른다.
--------------------------------------------------------------------------------
 
(18) 리펙토링
1. Source 메뉴에는 재미있는 기능이 많습니다.
- source =>Generate Getter and Setter를 보시면
그동안 여러분을 괴롭혔던 mutator와 accessor를 편하게 구현하실 방법이 들어있습니다.
- source => Generate Constructors using Fields에서는
class variable만 선언하면 constructor가 자동으로 만들어지게 해줍니다.
 
ALT + SHIFT + Z = 블록설정 후 try-catch 문 덮어서 만들어주기

(19) 디버깅
2. 버그가 있으십니까? 디버깅을 해보세요. (고급기능, 그러나 유용한 기능)
Ctrl+Shift+B를 누르면 breakpoint가 걸리고,
F11을 누르면 디버그 모드로 실행이 됩니다.
디 버그 모드에서는 breakpoint의 위치에서 어떤 변수가 어떤 값을 가지는지 볼 수 있고요,
한줄 한줄 실행해가며(보통 F6, 함수로 들어갈때 F5) 볼 수도 있고요.
디버깅에 대한 건 자세히 가면 책 한권정도 분량도 나오는데
기본적인 건 당연한 것들이 많아서 혼자 해보다 보면 스스로 많은 교훈을 얻으실 수 있습니다.
(자세한 도움이 필요하시면 메일을 보내시던지 주변에 물어보시고요 ^^)
아. 디버깅을 하시다보면 perspective(창의 배치)가 달라집니다.
이때 디버깅을 마치고 돌아오시려면 오른쪽 위에 Debug / Java라고 쓰인 곳에 가셔서 Java를 눌러주세요.
 
(20) 주석처리
Ctrl  +  Shift  +  /  -  instantly  toggling  comments
소 스를  일일히  주석처리  하는가.  블로  주석이라면  마우스로  긁어서  한번에  주석처리  하자.
 
(21) 기타
Alt  +Shift  +  T  -  Show  Refactor  Quick  Menu 
팝 업에  Refactor  선택에  명령어  수행  너무많은  시간이  소비된다.  한번에  단축키로  호출하자

(22) 단축키호출
Ctrl  +  Shift  +  L  -  Hotkeys  Table  Call
이클립스의  핫키  목록을  볼수있는  핫키
Eclipse 단축키 확인 및 변경
Eclipse 의 모든 단축키는 Window >> Preferences >> Workbench >> Keys 메뉴에서 확인 및 변경이 가능하다. 그 동안 다른 툴에서 자신의 손에 익숙한 단축키들이 있다면 이 메뉴에서 단축키들을 변경하는 것이 가능하다.
Java Editor 단축키
Ctrl + Shift + M : 캐럿이 위치한 대상에 필요한 특정 클래스 Import 시키기
Ctrl + Shift + O : 소스에 필요한 패키지를 자동으로 Import 시키기
Ctrl + Shift + F : 소스코드 자동 정리
Ctrl + Shift + G : 특정 메써드나 필드를 Reference하고 있는 곳을 찾는다.
Ctrl + Shift + K : 이전찾기 (또는, 찾고자하는 문자열을 블럭으로 설정한 후 역으로 찾고자 하는 문자열을 찾아감.)
Ctrl + shift + G : 특정 메써드나 필드를 참조하고 있는 곳을 찾는다.
Ctrl + shift + B : 현재커서위치에 Break point설정/해제
Ctrl + 1 : Quick Fix. 에러가 발생했을 경우 Quick Fix를 통해 쉽게 해결이 가능하다.(Rename에 주로 사용)
Ctrl + 2 + R : Rename (리팩토링)
Ctrl + Shift + / : 선택 영역 Block Comment 설정
Ctrl + Shift + : 선택 영역 Block Comment 제거
Ctrl + / : 한줄 또는 선택영역 주석처리 / 제거
Ctrl + S : 저장 및 컴파일
Ctrl + I : 소스 깔끔 정리(인덴트 중심의 자동구문정리)
Ctrl + space : 어휘의 자동완성(Content Assistance)
Ctrl + Q : 마지막 편집위치로 가기
Ctrl + L : 특정줄번호로 가기
Ctrl + D : 한줄삭제
Ctrl + O : Outline 창 열기
Ctrl + H : Find 및 Replace
Ctrl + K : 다음찾기(또는, 찾고자 하는 문자열을 블럭으로 설정한 후 키를 누른다.)
Ctrl + N : 새로운 파일 및 프로젝트 생성
Ctrl + Shift + S : 열려진 모든파일 저장 및 컴파일
Ctrl + 객체클릭(혹은 F3) : 클래스나 메소드 혹은 멤버를 정의한 곳으로 이동(Open Declaration)
Alt + Shift + UP : 커서를 기준으로 토큰단위 블럭지정 (괄호의 열고 닫기 쌍 확인에 유용)  ==> 괄호의 뒤에 마우스 커서를 위치시킨 후 더블클릭한 것과 같은 효과
Alt + Shift + DOWN : 커서를 기준으로 토큰단위 블럭해제
Alt + Shift + J : 설정해 둔 기본주석을 자동으로 달기 (메소드나 멤버변수에 포커스 두고 실행)
Alt + / : Word Completion
Alt + Shift + R : Rename
Alt + ->, Alt + <- : 이후, 이전
해당 프로젝트에서 Alt + Enter : Project 속성
sysout > Ctrl + Space : System.out.println();
try > Ctrl + Space : 기본 try-catch문 완성
for > Ctrl + Space : 기본 for문 완성
템플릿을 수정,추가 : Preferences > java > editor > Templates
Ctrl + Alt + R
Ctrl + F11 : 실행
F11 : 디버깅 시작
F5 : step into
F6 : step over
F8 : 디버깅 계속
Ctrl + .
 
 
(23) 에러위치로 이동 
Ctrl + '.'
 
(24) 키보드로 코드블럭 이동
 
Alt + 위 화살표 혹은 아래 화살표
 
(25) 나의 포맷 적용
 
Ctrl + Shift + 'F'

 

Posted by sungwonpekr