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

비밀번호

댓글 작성자
 




[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13609정성태4/27/2024206닷넷: 2250. PInvoke 호출 시 참조 타입(class)을 마샬링하는 [IN], [OUT] 특성파일 다운로드1
13608정성태4/26/2024424닷넷: 2249. C# - 부모의 필드/프로퍼티에 대해 서로 다른 자식 클래스 간에 Reflection 접근이 동작할까요?파일 다운로드1
13607정성태4/25/2024426닷넷: 2248. C# - 인터페이스 타입의 다중 포인터를 인자로 갖는 C/C++ 함수 연동
13606정성태4/24/2024493닷넷: 2247. C# - tensorflow 연동 (MNIST 예제)파일 다운로드1
13605정성태4/23/2024718닷넷: 2246. C# - Python.NET을 이용한 파이썬 소스코드 연동파일 다운로드1
13604정성태4/22/2024760오류 유형: 901. Visual Studio - Unable to set the next statement. Set next statement cannot be used in '[Exception]' call stack frames.
13603정성태4/21/2024908닷넷: 2245. C# - IronPython을 이용한 파이썬 소스코드 연동파일 다운로드1
13602정성태4/20/2024945닷넷: 2244. C# - PCM 오디오 데이터를 연속(Streaming) 재생 (Windows Multimedia)파일 다운로드1
13601정성태4/19/2024972닷넷: 2243. C# - PCM 사운드 재생(NAudio)파일 다운로드1
13600정성태4/18/2024990닷넷: 2242. C# - 관리 스레드와 비관리 스레드
13599정성태4/17/2024938닷넷: 2241. C# - WAV 파일의 PCM 사운드 재생(Windows Multimedia)파일 다운로드1
13598정성태4/16/2024981닷넷: 2240. C# - WAV 파일 포맷 + LIST 헤더파일 다운로드2
13597정성태4/15/2024978닷넷: 2239. C# - WAV 파일의 PCM 데이터 생성 및 출력파일 다운로드1
13596정성태4/14/20241085닷넷: 2238. C# - WAV 기본 파일 포맷파일 다운로드1
13595정성태4/13/20241071닷넷: 2237. C# - Audio 장치 열기 (Windows Multimedia, NAudio)파일 다운로드1
13594정성태4/12/20241090닷넷: 2236. C# - Audio 장치 열람 (Windows Multimedia, NAudio)파일 다운로드1
13593정성태4/8/20241092닷넷: 2235. MSBuild - AccelerateBuildsInVisualStudio 옵션
13592정성태4/2/20241229C/C++: 165. CLion으로 만든 Rust Win32 DLL을 C#과 연동
13591정성태4/2/20241204닷넷: 2234. C# - WPF 응용 프로그램에 Blazor App 통합파일 다운로드1
13590정성태3/31/20241085Linux: 70. Python - uwsgi 응용 프로그램이 k8s 환경에서 OOM 발생하는 문제
13589정성태3/29/20241163닷넷: 2233. C# - 프로세스 CPU 사용량을 나타내는 성능 카운터와 Win32 API파일 다운로드1
13588정성태3/28/20241518닷넷: 2232. C# - Unity + 닷넷 App(WinForms/WPF) 간의 Named Pipe 통신 [2]파일 다운로드1
13587정성태3/27/20241395오류 유형: 900. Windows Update 오류 - 8024402C, 80070643
13586정성태3/27/20241596Windows: 263. Windows - 복구 파티션(Recovery Partition) 용량을 늘리는 방법
13585정성태3/26/20241502Windows: 262. PerformanceCounter의 InstanceName에 pid를 추가한 "Process V2"
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...