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

비밀번호

댓글 작성자
 




... 46  47  48  49  [50]  51  52  53  54  55  56  57  58  59  60  ...
NoWriterDateCnt.TitleFile(s)
12687정성태6/22/202114977오류 유형: 729. Invalid data: Invalid artifact, java se app service only supports .jar artifact
12686정성태6/21/202116937Java: 22. Azure - 자바(Java)로 만드는 Web App Service - Java SE (Embedded Web Server) 호스팅
12685정성태6/21/202118144Java: 21. Azure Web App Service에 배포된 Java 프로세스의 메모리 및 힙(Heap) 덤프 뜨는 방법
12684정성태6/19/202116494오류 유형: 728. Visual Studio 2022부터 DTE.get_Properties 속성 접근 시 System.MissingMethodException 예외 발생
12683정성태6/18/202117820VS.NET IDE: 166. Visual Studio 2022 - Windows Forms 프로젝트의 x86 DLL 컨트롤이 Designer에서 오류가 발생하는 문제 [1]파일 다운로드1
12682정성태6/18/202114359VS.NET IDE: 165. Visual Studio 2022를 위한 Extension 마이그레이션
12681정성태6/18/202114636오류 유형: 727. .NET 2.0 ~ 3.5 + x64 환경에서 System.EnterpriseServices 참조 시 CS8012 경고
12680정성태6/18/202116703오류 유형: 726. python2.7.exe 실행 시 0xc000007b 오류
12679정성태6/18/202116813COM 개체 관련: 23. CoInitializeSecurity의 전역 설정을 재정의하는 CoSetProxyBlanket 함수 사용법파일 다운로드1
12678정성태6/17/202115310.NET Framework: 1072. C# - CoCreateInstance 관련 Inteop 오류 정리파일 다운로드1
12677정성태6/17/202118095VC++: 144. 역공학을 통한 lxssmanager.dll의 ILxssSession 사용법 분석파일 다운로드1
12676정성태6/16/202117266VC++: 143. ionescu007/lxss github repo에 공개된 lxssmanager.dll의 CLSID_LxssUserSession/IID_ILxssSession 사용법파일 다운로드1
12675정성태6/16/202115159Java: 20. maven package 명령어 결과물로 (war가 아닌) jar 생성 방법
12674정성태6/15/202116418VC++: 142. DEFINE_GUID 사용법
12673정성태6/15/202117020Java: 19. IntelliJ - 자바(Java)로 만드는 Web App을 Tomcat에서 실행하는 방법
12672정성태6/15/202118641오류 유형: 725. IntelliJ에서 Java webapp 실행 시 "Address localhost:1099 is already in use" 오류
12671정성태6/15/202127316오류 유형: 724. Tomcat 실행 시 Failed to initialize connector [Connector[HTTP/1.1-8080]] 오류
12670정성태6/13/202117286.NET Framework: 1071. DLL Surrogate를 이용한 Out-of-process COM 개체에서의 CoInitializeSecurity 문제파일 다운로드1
12669정성태6/11/202117487.NET Framework: 1070. 사용자 정의 GetHashCode 메서드 구현은 C# 9.0의 record 또는 리팩터링에 맡기세요.
12668정성태6/11/202119968.NET Framework: 1069. C# - DLL Surrogate를 이용한 Out-of-process COM 개체 제작파일 다운로드2
12667정성태6/10/202117788.NET Framework: 1068. COM+ 서버 응용 프로그램을 이용해 CoInitializeSecurity 제약 해결파일 다운로드1
12666정성태6/10/202115423.NET Framework: 1067. 별도 DLL에 포함된 타입을 STAThread Main 메서드에서 사용하는 경우 CoInitializeSecurity 자동 호출파일 다운로드1
12665정성태6/9/202117486.NET Framework: 1066. Wslhub.Sdk 사용으로 알아보는 CoInitializeSecurity 사용 제약파일 다운로드1
12664정성태6/9/202115281오류 유형: 723. COM+ PIA 참조 시 "This operation failed because the QueryInterface call on the COM component" 오류
12663정성태6/9/202117669.NET Framework: 1065. Windows Forms - 속성 창의 디자인 설정 지원: 문자열 목록 내에서 항목을 선택하는 TypeConverter 제작파일 다운로드1
12662정성태6/8/202115403.NET Framework: 1064. C# COM 개체를 PIA(Primary Interop Assembly)로써 "Embed Interop Types" 참조하는 방법파일 다운로드1
... 46  47  48  49  [50]  51  52  53  54  55  56  57  58  59  60  ...