Передача двухстороннего объекта с помощью jni4net (была: Ignore Missing Class (es)) - PullRequest
4 голосов
/ 05 августа 2010

Я использую jni4net для доступа к коду Java из приложения C # и наоборот. jni4net использует отражение для генерации прокси-серверов JNI-кода, поэтому одно из ограничений состоит в том, что ваш код на Java и C # должен компилироваться для создания прокси.

К сожалению, это может привести к проблеме catch-22. Рассмотрим:

C # класс X использует класс Java Y
Java класс Y использует C # класс X

Ни один из них не может быть скомпилирован, поэтому хорошо зарекомендовавший себя способ состоит в том, чтобы взять один из классов (X или Y), разделить его до его чистой подписи и заставить его скомпилировать, а затем сгенерировать прокси из скомпилированного скелета. Затем вы можете заменить раздетый класс на оригинальный и продолжить свой веселый путь.

Это кажется мне отвратительным подходом, и я считаю, что должен быть лучший путь. Очевидным решением было бы сказать компилятору (или C #, или Java, на самом деле не имеет значения, какой) игнорировать ссылки на отсутствующий класс.

Возможно ли игнорирование ссылок на определенный отсутствующий класс для компиляторов C # или Java? Есть ли лучший способ сделать это (и нет, я не открыт для рассмотрения сокетов или чего-то подобного; мне требуется настоящее взаимодействие между .NET и Java)?

Пример кода был запрошен:

Пример кода с удаленным кодом моста jni4net для ясности. IA и IB - простые интерфейсы, также не включенные.

Java:

public class A implements IA  
{  
    public void m1()  
    {  
        System.out.println("m1 called");  
    }  

    public static void main (String args[])  
    {  
        IB b = new B();  
        b.m2(new A());  
    }  
}  

C #:

public class B : IB  
{  
    public void m2(IA a)  
    {  
        a.m1();  
        A a2 = new A();  
        a2.m1();  
    }  
}  

Ответы [ 2 ]

4 голосов
/ 06 августа 2010

Я решил проблему самостоятельно.Это не связано с моей первоначальной догадкой, поэтому я изменил название этой проблемы, чтобы лучше отразить актуальную проблему.

Хотя в пакете jni4net есть много полезных примеров, похоже, не было хороших примеровобъект, проходящий в обоих направлениях без какой-либо странной гимнастики сборки (см. оригинальную постановку задачи).Я понял, как это сделать, и представил решение здесь вместе с командами, необходимыми для построения результата.

Самый простой способ запустить это - настроить jni4net, как сказано в инструкциях, и отбросить все эти вещи.в новый подкаталог примера каталога, который поставляется с пакетом jni4net.

Сначала код C #:

src / test / left.cs

namespace test
{
    using System;
    using net.sf.jni4net;
    using test;

    public class left : iright
    {
        public static void Main(String[] args)
        {
            left l = new left();
            l.sendMeToRight();
        }

        public left()
        {
            Console.WriteLine("left side constructed...");
        }

        public void sendMeToRight()
        {
            BridgeSetup bridgeSetup = new BridgeSetup();
            bridgeSetup.AddAllJarsClassPath(".");
            Bridge.CreateJVM(bridgeSetup);
            Bridge.RegisterAssembly(typeof(right).Assembly);

            Console.WriteLine("Sending myself to right.");
            right il = new right(this);
            il.announceMyself();
        }

        public void announceMyself()
        {
            Console.WriteLine("Hello from the left side...");
        }
    }
}

А теперь код Java:

src / test / iright.java

package test;

public interface iright
{
    void announceMyself();
}

src / test / right.java

package test;

public class right implements iright
{
    public right(iright f)
    {
        System.out.println("right side constructed... ");
    f.announceMyself();
    }

    public void announceMyself()
    {
        System.out.println("Hello from the right side...");  
    }    
}

И, наконец, скрипт сборки (я собрал его для запуска в cygwin и в очень короткие сроки, поэтому изменяйте по мере необходимости.):

@echo off
rm -rf build
mkdir build
mkdir build\test
copy ..\..\lib\*.* build

echo Compile base classes.
javac src/test/*.java
mv src/test/*.class build/test

echo Creating jar file.
jar cvf build\lr.jar -C build test/iright.class -C build test/right.class
rm build/test/*.class

echo Generating proxies.
..\..\bin\proxygen.exe build\lr.jar -wd build

echo Compiling derived proxy classes.
javac -cp build\lr.jar;build\jni4net.j-0.8.0.0.jar build\jvm\test\iright_.java build\jvm\test\right_.java

echo Packing compiled derived proxy classes.
jar cvf build\lr.j4n.jar -C build\jvm test\__iright.class -C build\jvm test\iright_.class -C build\jvm test\right_.class

echo Generating derived proxy DLL.
cd build
csc.exe /nologo /warn:0 /t:library /out:lr.j4n.dll /recurse:clr\*.cs /reference:"c:\windows\microsoft.net\framework\v2.0.50727\mscorlib.dll" /reference:jni4net.n-0.8.0.0.dll

echo Generating product executable.
csc.exe /nologo /warn:0 /out:demo.exe /target:exe /reference:jni4net.n-0.8.0.0.dll /reference:lr.j4n.dll ..\src\test\left.cs
0 голосов
/ 05 августа 2010

В C # 4 вы можете использовать динамическое ключевое слово при доступе к объекту Java. Точно не попробовал ваш сценарий. Некоторый пример кода поможет.

изменить для обновленного вопроса
У вас круговая зависимость, на которую, скорее всего, будет жаловаться один компилятор, не говоря уже о двух. Рефакторинг на что-то более похожее на следующее поможет. Конечно, это не так просто в вашем реальном коде.

// java
public class A implements IA  
{  
    public void m1()  
    {  
        System.out.println("m1 called");  
    }  
}

public class MainClass
{
    public static void main (String args[])  
    {  
        IB b = new B();  
        b.m2(new A());  
    }  
}  

//C#

public class B : IB  
{  
    public void m2(IA a)  
    {  
        a.m1();  
        A a2 = new A();  
        a2.m1();  
    }  
}
...