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

비밀번호

댓글 작성자
 




... 136  137  138  139  140  141  142  143  [144]  145  146  147  148  149  150  ...
NoWriterDateCnt.TitleFile(s)
1454정성태5/31/201326227Java: 15. Java 7 Control Panel 실행시키는 방법
1453정성태5/22/201325236기타: 32. Microsoft FTP 사이트에 접속하는 방법
1452정성태5/21/201332945Windows: 73. TabProcGrowth 값 삭제 후 IE를 실행시키면 다시 복원되는 경우 [3]
1451정성태5/17/201331881Windows: 72. 윈도우 서버 2012 기초 사용법
1450정성태5/16/201322700오류 유형: 176. SQL10007N Message "0" could not be retrieved. Reason code: "3"
1449정성태5/15/201329821오류 유형: 175. SpeechRecognitionEngine 사용 시 오류 유형 2가지
1448정성태5/14/201324800VC++: 68. #pragma warning(disable: ...)로 오류 제어가 안된다면?
1447정성태5/3/201326462개발 환경 구성: 191. Debugging Tools for Windows 독립 설치 버전 [1]
1446정성태4/30/201327237.NET Framework: 368. Encoding 타입의 대체(fallback) 메카니즘 [1]
1445정성태4/26/201325451디버깅 기술: 54. NT 서비스의 Main 메서드 안에서 Process.GetProcessesByName 호출 시 멈춤 현상 [1]
1444정성태4/26/201329484기타: 31. Internet Explorer: 자바스크립트로 숨겨진 파일 다운로드 경로를 알아내는 방법 [1]
1443정성태4/24/201325144개발 환경 구성: 190. Azure PaaS 웹 응용 프로그램 배포 후 SMTP 서버 구성 [2]
1442정성태4/21/201328728기타: 30. 마이크로소프트 워드의 CPU 점유 현상으로 글자 입력이 느려졌다면? [1]
1441정성태4/21/201335334.NET Framework: 367. LargeAddressAware 옵션이 적용된 닷넷 32비트 프로세스의 가용 메모리 [14]
1440정성태4/19/201324062오류 유형: 174. dumpbin.exe 실행시 mspdb110.dll 로드 오류
1439정성태4/18/201327916VS.NET IDE: 76. Visual Studio 2012와 Itanium 빌드 옵션 [2]
1438정성태4/17/201327305.NET Framework: 366. 다른 프로세스에 환경 변수 설정하는 방법 - 두 번째 이야기 [1]파일 다운로드1
1437정성태4/17/201327534VC++: 67. CRT(C Runtime DLL: msvcr...dll)에 대한 의존성 제거
1436정성태4/17/201332958.NET Framework: 365. Local SYSTEM 권한으로 코드를 실행하는 방법파일 다운로드1
1435정성태4/15/201341841Windows: 71. ad-hoc 보다 더 편리한 "가상 Wifi" 를 이용한 인터넷 공유 [2]
1434정성태4/9/201323119오류 유형: 173. TFS 서버의 이벤트 로그 오류 - WebHost failed to process a request. Parameter name: certificate
1433정성태4/9/201323400개발 환경 구성: 189. TFS에 설치된 SharePoint 의 PowerShell 콘솔 띄우는 방법
1432정성태4/5/201324411오류 유형: 172. System.Web.PipelineModuleStepContainer.GetEventCount 에서 NullReferenceException 이 발생한다면?
1431정성태4/5/201325060기타: 29. 부팅 가능한 (외장) HDD를 기존 부팅 메뉴에 추가하는 방법
1430정성태4/4/201326898제니퍼 .NET: 23. 모바일용 웹 사이트에서 발생하는 응답 시간 지연 현상 [5]파일 다운로드1
1429정성태3/29/201323270개발 환경 구성: 188. SCOM 2012 - ASP.NET 모니터링 방법
... 136  137  138  139  140  141  142  143  [144]  145  146  147  148  149  150  ...