Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)

JNBridgePro를 이용해 C#에서 Java메서드 호출 테스트

페이스북 지인을 통해 JNIBridge를 알게 되었습니다. ^^ 이 제품은 닷넷과 자바 상호 간의 호출을 가능하게 해준다고 하는데 흥미로워서 테스트를 해보았습니다. ^^




아래와 같은 환경의 PC를 준비하고,

  • Visual Studio 2013
  • JDK 7 x86
  • .NET Framework 4

웹 사이트에서 JNBridgePro를 Free Trial로 신청한 후,

JNBridgePro
; http://www.jnbridge.com/

다운로드한 JNBSetup7_1.msi 파일을 설치하고 "JNBProxy v7.1 proxy generation tool (.NET 4.0-targeted)" 프로그램을 실행시켜 java.exe 경로를 맞춰주었습니다.

jnibridge_pro_1.png

그다음 화면으로 넘어가면 "Online License Activation" 탭을 선택해 등록 시에 입력했던 주소로 날아온 라이선스 키를 활성화시킬 수 있습니다.

jnibridge_pro_2.png




일단 라이선스 활성화를 시키면 이후에는 실행할 때마다 코드 생성 관련한 단계로 곧바로 넘어갑니다.

jnibridge_pro_3.png

여기서는 HanNanum 자바 라이브러리를 호출할 것이므로 첫 번째 "Create new .Net -> Java project"를 선택하고 OK 버튼을 누르면 다음과 같은 화면이 나옵니다.

jnibridge_pro_4.png

"Project" / "Edit Classpath..." 메뉴를 이용해 "jhannanum.jar" 파일과 그 폴더를 class path에 등록해 줍니다.

jnibridge_pro_5.png

그다음, "Project" / "Add Classes from JAR..." 메뉴를 실행해 jhannanum.jar 파일을 선택해 주면 jar 파일 및 그에 대한 의존성을 분석해 "Environment" 트리에 출력해 줍니다.

참고로, 이 과정에서 이런 내용의 오류 메시지가 뜰 수 있습니다.

The operation could not be completed because the following Java classes or classes on which they were dependent could not be found

jnbridge 측의 설명은 대개의 경우 무시해도 좋다고 합니다.

Loading jar files: “Missing classes”
; http://www.jnbridge.com/jn/kb/?p=15

거의 다 왔습니다. ^^ 이제 생성할 proxy 클래스를 지정해야 하는데요.HanNanum 라이브러리에 따라 kr.ac.kaist에 해당하는 모든 항목을 선택하고 "Add" 버튼을 눌러주었습니다.

jnibridge_pro_6.png

마지막으로 선택된 proxy 클래스를 빌드해서 닷넷 DLL로 만들어 주어야 합니다. 이를 위해 "Project" / "Build..." 메뉴를 선택해 새롭게 DLL 이름을 지정하면 해당 어셈블리가 생성됩니다.




이제 본격적으로 proxy dll을 닷넷 프로젝트에서 사용해 볼까요? 비교를 위해 NHanNanum 글에 첨부한 프로젝트에서 어떻게 변경해야 하는지 살펴보겠습니다.

우선, .NET 프로젝트로 포팅했던 NHanNanum 프로젝트를 제거하고 새롭게 생성한 proxy dll과 함께 jnbridge 측에서 제공해주는 또 다른 어셈블리인 JNBShare.dll, JNBSharedMem_x86.dll 파일을 참조 추가해야 합니다. (JNB 관련 파일들은 "C:\Program Files (x86)\JNBridge\JNBridgePro v7.1\4.0-targeted" 폴더에서 구할 수 있습니다.)

참조 추가는 그렇게 3개만 해주면 되지만 EXE가 정상적으로 실행되기 위해서는 동일한 폴더에 다음과 같은 파일들이 배포되어야 합니다.

  • JAVA 실행 원본 파일인 jhannanum.jar
  • rlm932_x86.dll - "C:\Program Files (x86)\JNBridge\JNBridgePro v7.1\4.0-targeted" 폴더에 있음.
  • jnbcore.jar - "C:\Program Files (x86)\JNBridge\JNBridgePro v7.1\jnbcore" 폴더에 있음.
  • bcel-5.1-jnbridge.jar - "C:\Program Files (x86)\JNBridge\JNBridgePro v7.1\jnbcore" 폴더에 있음.

위의 파일들은 "Add as Link"로 프로젝트에 추가한 후 "Copy to Output Directory" 옵션을 "Copy if newer"로 설정해 주면 됩니다.

그다음 app.config 파일을 추가해 jnbridge 관련 설정을 넣어줍니다.


<configuration>
  <configSections>
      <sectionGroup name="jnbridge">
          <section name="dotNetToJavaConfig"
                  type="System.Configuration.SingleTagSectionHandler, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
          <section name="javaToDotNetConfig"
                  type="System.Configuration.SingleTagSectionHandler, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
          <section name="tcpNoDelay"
                  type="System.Configuration.SingleTagSectionHandler, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
          <section name="javaSideDeclarations"
                  type="System.Configuration.NameValueSectionHandler, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
      </sectionGroup>
  </configSections>
  <jnbridge>
  <dotNetToJavaConfig scheme="sharedmem"
     jvm="C:\Program Files (x86)\Java\jre7\bin\client\jvm.dll"
     jnbcore="jnbcore.jar"
     bcel="bcel-5.1-jnbridge.jar"
     classpath="jhannanum.jar" />
  </jnbridge>
</configuration>  

보시는 바와 같이 애매한 점이 하나 있습니다. jnbcore.jar, bcel-5.1-jnbridge.jar 등의 파일은 같은 폴더에 배포하면 되지만 jvm.dll을 저렇게 위치 고정한다는 것이 현실적으로 그리 타당한 방법은 아닐 것 같습니다. jvm.dll도 exe가 위치한 폴더로 복사해서 실행하면 개발자 PC에서야 되겠지만 JRE 1.6이 설치된 PC에서도 잘 실행될지는 의문입니다.

프로젝트 준비는 이것으로 됐고 문제는 소스코드입니다. NHanNanum 글에 첨부한 소스코드는 자바 라이브러리를 C#으로 포팅했기 때문에 가능한 것이고 여기서는 jnbridge의 proxy 클래스를 이용하는 것이므로 몇몇 시그니처가 달라지는 점이 있습니다.

예를 들어, workflow.getResultOfDocument의 반환값이 LinkedList<Sentence> 타입이 아닌 object로 바뀝니다. 이런저런 오류를 수정하고 나면 최종적으로 테스트 코드는 다음과 같이 변경됩니다.

static void Main(string[] args)
{
    Workflow workflow = WorkflowFactory.getPredefinedWorkflow(WorkflowFactory.WORKFLOW_NOUN_EXTRACTOR);

    try
    {
        workflow.activateWorkflow(true);

        // string doc = GetWebPage("http://ko.wikipedia.org/wiki/%EC%9D%B8%ED%84%B0%EB%84%B7");
        //HtmlToText htt = new HtmlToText();
        //string document = htt.ConvertHtml(doc);

        string document = File.ReadAllText("sample.txt");
        StringBuilder sb = new StringBuilder();

        workflow.analyze(document);

        object obj = workflow.getResultOfDocument(new Sentence(0, 0, false));
        java.util.LinkedList result = obj as java.util.LinkedList;
        int length = result.size();

        for (int idx = 0; idx < length; idx++)
        {
            Sentence s = result.get(idx) as Sentence;

            Eojeol[] eojeolarray = s.getEojeols();
            for (int i = 0; i < eojeolarray.Length; i++)
            {
                if (eojeolarray[i].length > 0)
                {
                    string[] morphemes = eojeolarray[i].getMorphemes();
                    for (int j = 0; j < morphemes.Length; j++)
                    {
                        sb.Append(morphemes[j]);
                        sb.Append(", ");
                    }
                }
            }
        }

        Console.WriteLine(sb.ToString());

        workflow.close();

    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
        return;
    }

    /* Shutdown the work flow */
    workflow.close();
}

뭐 그런대로 소스코드 변경 사항은 그다지 나쁘지 않습니다. ^^ 이제 실행할 일만 남았죠? ^^

하지만, 아쉽게도 다음과 같은 식의 오류가 발생합니다.

org.json.JSONException: Unterminated string at 101 [character 22 line 6]

대충 보아하니 ChartMorphAnalyzer.json 파일의 6번째 라인에 한글이 포함된 것을 분석하지 못하는 것으로 보입니다. 그래서, (한글 라이브러리에서 한글을 없애는 것이 말도 안되지만) ./conf, ./data 폴더 하위에 있는 모든 파일로부터 한글을 없애고 다시 실행해 보았습니다.

결과는? 정상적으로 실행은 되었습니다. 물론 한글 형태소 분석기라는 취지상 출력은 다소 비정상적이지만, 어쨌든 .NET에서 Java로의 호출이 가능한 것은 확인이 되었습니다. 한글 문제만 적절하게 해결된다면 JNIBridge는 나름 괜찮은 해법이 될 수도 있을 것 같습니다. (예제 테스트 프로젝트는 첨부했으니 참고하세요. ^^)

참고로, 위의 내용은 모두 jnbridge 측에서 제공하는 비디오 예제에 담겨 있기도 합니다.

DEMO - Access Java from .NET: Tutorial I
; http://www.jnbridge.com/LogDemoProxyGenVideo.htm

Access Java from .NET Tutorial II: Proxy Usage
; http://www.jnbridge.com/LogDemoProxyUseVideo.htm




오류 정리입니다.

"The type initializer for 'com.jnbridge.jnbcore.ObjectWrapper' threw an exception." 오류가 발생할 수 있는데요.

System.TypeInitializationException was unhandled
  HResult=-2146233036
  Message=The type initializer for 'com.jnbridge.jnbcore.ObjectWrapper' threw an exception.
  Source=JNBShare
  TypeName=com.jnbridge.jnbcore.ObjectWrapper
  StackTrace:
       at com.jnbridge.jnbcore.ObjectWrapper.get_statJnbDispatcher()
       at kr.ac.kaist.swrc.jhannanum.hannanum.WorkflowFactory.get_WORKFLOW_NOUN_EXTRACTOR()
       at DemoApp.Program.Main(String[] args) in c:\temp\NHanNanum\DemoApp\Program.cs:line 18
  InnerException: System.TypeInitializationException
       HResult=-2146233036
       Message=The type initializer for 'com.jnbridge.jnbcore.ObjectHelper' threw an exception.
       Source=JNBShare
       TypeName=com.jnbridge.jnbcore.ObjectHelper
       StackTrace:
            at com.jnbridge.jnbcore.ObjectWrapper..cctor()
       InnerException: System.TypeInitializationException
            HResult=-2146233036
            Message=The type initializer for 'com.jnbridge.jnbproxy.ProxyAssembly' threw an exception.
            Source=JNBShare
            TypeName=com.jnbridge.jnbproxy.ProxyAssembly
            StackTrace:
                 at com.jnbridge.jnbproxy.ProxyAssembly..ctor()
                 at com.jnbridge.jnbcore.ObjectHelper..cctor()
            InnerException: com.jnbridge.jnbcore.InvalidLicenseException
                 HResult=-2146232832
                 Message=Could not find the library in the following error message. Please make sure that it is in the startup directory of your application. Error: Unable to load DLL 'rlm932_x86.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
                 Source=JNBShare
                 StackTrace:
                      at com.jnbridge.jnbproxy.proxym.RLMProductionLicenseManager.initializeAndLoadLicense(String licenseLocation)
                      at com.jnbridge.jnbproxy.proxym.RLMProductionLicenseManager.loadLicense()
                      at com.jnbridge.jnbproxy.proxym.RLMProductionLicenseManager..ctor()
                      at com.jnbridge.jnbproxy.proxym.ProxyMFactory.getInstance(String lmType)
                      at com.jnbridge.jnbproxy.ProxyAssembly..cctor()
                 InnerException: 

.NET 실행 파일과 같은 폴더에 rlm932_x86.dll 파일이 없어서 발생하는 것입니다. "C:\Program Files (x86)\JNBridge\JNBridgePro v7.1\4.0-targeted" 폴더에 가면 rlm...dll 파일을 구할 수 있고 이를 함께 배포해 주어야 합니다.

다음으로 config 관련 오류가 발생할 수 있습니다.

System.TypeInitializationException was unhandled
  HResult=-2146233036
  Message=The type initializer for 'com.jnbridge.jnbcore.ObjectWrapper' threw an exception.
  Source=JNBShare
  TypeName=com.jnbridge.jnbcore.ObjectWrapper
  StackTrace:
       at com.jnbridge.jnbcore.ObjectWrapper.get_statJnbDispatcher()
       at kr.ac.kaist.swrc.jhannanum.hannanum.WorkflowFactory.get_WORKFLOW_NOUN_EXTRACTOR()
       at DemoApp.Program.Main(String[] args) in c:\temp\NHanNanum\DemoApp\Program.cs:line 18
  InnerException: System.TypeInitializationException
       HResult=-2146233036
       Message=The type initializer for 'com.jnbridge.jnbcore.ObjectHelper' threw an exception.
       Source=JNBShare
       TypeName=com.jnbridge.jnbcore.ObjectHelper
       StackTrace:
            at com.jnbridge.jnbcore.ObjectHelper.assemblyLoadEventHandler(Object sender, AssemblyLoadEventArgs args)
            at System.AppDomain.OnAssemblyLoadEvent(RuntimeAssembly LoadedAssembly)
       InnerException: System.TypeInitializationException
            HResult=-2146233036
            Message=The type initializer for 'com.jnbridge.jnbproxy.JavaSides' threw an exception.
            Source=JNBShare
            TypeName=com.jnbridge.jnbproxy.JavaSides
            StackTrace:
                 at com.jnbridge.jnbproxy.JavaSides.getInitialEntry()
                 at com.jnbridge.jnbcore.ObjectHelper..cctor()
            InnerException: System.ApplicationException
                 HResult=-2146232832
                 Message=.NET-side configuration information is missing.  Should be in application configuration file, jnbproxy.config, or supplied programmatically.  See the Users' Guide for more information.
                 Source=JNBShare
                 StackTrace:
                      at com.jnbridge.jnbproxy.JNBRemotingConfiguration.Configure()
                      at com.jnbridge.jnbproxy.JavaSides..cctor()
                 InnerException: 

이건 app.config에 구성을 포함하지 않아서 발생하는 것입니다.






[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 6/28/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 121  122  123  124  125  126  127  [128]  129  130  131  132  133  134  135  ...
NoWriterDateCnt.TitleFile(s)
1855정성태2/10/201520712개발 환경 구성: 256. WebDAV Redirector - Sysinternals 폴더 연결 시 "The network path was not found" 오류 해결 방법
1854정성태2/10/201521688Windows: 104. 폴더는 삭제할 수 없지만, 그 하위 폴더/파일은 생성/삭제/변경하는 보안 설정
1853정성태2/6/201551972웹: 29. 여신금융협회 웹 사이트의 "Netscape 6.0은 지원하지 않습니다." 오류 메시지 [5]
1852정성태2/5/201522368.NET Framework: 492. .NET CLR Memory 성능 카운터의 의미파일 다운로드1
1851정성태2/5/201523351VC++: 88. 하룻밤의 꿈 - 인텔 하스웰의 TSX Instruction 지원 [2]
1850정성태2/4/201544160Windows: 103. 작업 관리자에서의 "Commit size"가 가리키는 메모리의 의미 [4]
1849정성태2/4/201524099기타: 51. DropBox의 CPU 100% 현상 [1]파일 다운로드1
1848정성태2/4/201519324.NET Framework: 491. 닷넷 Generic 타입의 메타 데이터 토큰 값 알아내는 방법 [2]
1847정성태2/3/201522673기타: 50. C# - 윈도우에서 dropbox 동기화 폴더 경로 및 종료하는 방법
1846정성태2/2/201531960Windows: 102. 제어판의 프로그램 추가/삭제 항목을 수동으로 실행하고 싶다면? [1]
1845정성태1/26/201532848Windows: 101. 제어판의 "Windows 자격 증명 관리(Manage your credentials)"를 금지시키는 방법
1844정성태1/26/201530794오류 유형: 269. USB 메모리의 용량이 비정상적으로 보여진다면? [7]
1843정성태1/24/201521801VC++: 87. 무시할 수 없는 Visual C++ 런타임 함수 성능
1842정성태1/23/201544304개발 환경 구성: 255. 노트북 키보드에 없는 BREAK 키를 다른 키로 대체하는 방법
1841정성태1/21/201519260오류 유형: 268. Win32 핸들 관련 CLR4 보안 오류 사례
1840정성태1/8/201527509오류 유형: 267. Visual Studio - CodeLens 사용 시 CPU 100% 현상
1839정성태1/5/201520410디버깅 기술: 69. windbg 분석 사례 - cpu 100% 현상 (2)
1838정성태1/4/201540158기타: 49. 윈도우 내레이터(Narrator) 기능 끄는 방법(윈도우에 파란색의 굵은 테두리 선이 나타난다면?) [4]
1837정성태1/4/201526282디버깅 기술: 68. windbg 분석 사례 - 메모리 부족 [1]
1836정성태1/4/201526273디버깅 기술: 67. windbg - 덤프 파일과 handle 정보
1835정성태1/3/201526756개발 환경 구성: 254. SQL 서버 역시 SSL 3.0/TLS 1.0만을 지원하는 듯!
1834정성태1/3/201551398개발 환경 구성: 253. TLS 1.2를 적용한 IIS 웹 사이트 구성
1833정성태1/3/201527452.NET Framework: 490. System.Data.SqlClient는 SSL 3.0/TLS 1.0만 지원하는 듯! [3]
1832정성태1/2/201520524오류 유형: 266. Azure에 응용 프로그램 게시 중 로그인 오류
1831정성태1/1/201528408디버깅 기술: 66. windbg 분석 사례 - cpu 100% 현상 (1) [1]
1830정성태1/1/201527438오류 유형: 265. svchost.exe 프로세스(IP Helper: IPHLPSVC)의 CPU 100% 현상
... 121  122  123  124  125  126  127  [128]  129  130  131  132  133  134  135  ...