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)
13521정성태1/11/20242399닷넷: 2199. C# - 한국투자증권 KIS Developers OpenAPI의 WebSocket Ping, Pong 처리
13520정성태1/10/20242180오류 유형: 888. C# - Unable to resolve service for type 'Microsoft.Extensions.ObjectPool.ObjectPool`....'
13519정성태1/10/20242220닷넷: 2198. C# - Reflection을 이용한 ClientWebSocket의 Ping 호출파일 다운로드1
13518정성태1/9/20242483닷넷: 2197. C# - ClientWebSocket의 Ping, Pong 처리
13517정성태1/8/20242295스크립트: 63. Python - 공개 패키지를 이용한 위성 이미지 생성 (pystac_client, odc.stac)
13516정성태1/7/20242404닷넷: 2196. IIS - AppPool의 "Disable Overlapped Recycle" 옵션의 부작용
13515정성태1/6/20242722닷넷: 2195. async 메서드 내에서 C# 7의 discard 구문 활용 사례 [1]
13514정성태1/5/20242383개발 환경 구성: 702. IIS - AppPool의 "Disable Overlapped Recycle" 옵션
13513정성태1/5/20242308닷넷: 2194. C# - WebActivatorEx / System.Web의 PreApplicationStartMethod 특성
13512정성태1/4/20242257개발 환경 구성: 701. IIS - w3wp.exe 프로세스의 ASP.NET 런타임을 항상 Warmup 모드로 유지하는 preload Enabled 설정
13511정성태1/4/20242261닷넷: 2193. C# - ASP.NET Web Application + OpenAPI(Swashbuckle) 스펙 제공
13510정성태1/3/20242180닷넷: 2192. C# - 특정 실행 파일이 있는지 확인하는 방법 (Linux)
13509정성태1/3/20242251오류 유형: 887. .NET Core 2 이하의 프로젝트에서 System.Runtime.CompilerServices.Unsafe doesn't support netcoreapp2.0.
13508정성태1/3/20242309오류 유형: 886. ORA-28000: the account is locked
13507정성태1/2/20242981닷넷: 2191. C# - IPGlobalProperties를 이용해 netstat처럼 사용 중인 Socket 목록 구하는 방법파일 다운로드1
13506정성태12/29/20232560닷넷: 2190. C# - 닷넷 코어/5+에서 달라지는 System.Text.Encoding 지원
13505정성태12/27/20233129닷넷: 2189. C# - WebSocket 클라이언트를 닷넷으로 구현하는 예제 (System.Net.WebSockets)파일 다운로드1
13504정성태12/27/20232696닷넷: 2188. C# - ASP.NET Core SignalR로 구현하는 채팅 서비스 예제파일 다운로드1
13503정성태12/27/20232584Linux: 67. WSL 환경 + mlocate(locate) 도구의 /mnt 디렉터리 검색 문제
13502정성태12/26/20232639닷넷: 2187. C# - 다른 프로세스의 환경변수 읽는 예제파일 다운로드1
13501정성태12/25/20232403개발 환경 구성: 700. WSL + uwsgi - IPv6로 바인딩하는 방법
13500정성태12/24/20232524디버깅 기술: 194. Windbg - x64 가상 주소를 물리 주소로 변환
13498정성태12/23/20233190닷넷: 2186. 한국투자증권 KIS Developers OpenAPI의 C# 래퍼 버전 - eFriendOpenAPI NuGet 패키지
13497정성태12/22/20232594오류 유형: 885. Visual Studiio - error : Could not connect to the remote system. Please verify your connection settings, and that your machine is on the network and reachable.
13496정성태12/21/20232693Linux: 66. 리눅스 - 실행 중인 프로세스 내부의 환경변수 설정을 구하는 방법 (gdb)
13495정성태12/20/20232627Linux: 65. clang++로 공유 라이브러리의 -static 옵션 빌드가 가능할까요?
1  2  3  4  [5]  6  7  8  9  10  11  12  13  14  15  ...