تم بناء JCOBridge على رأس مكون DLR الإضافي المعتمد ميدانيًا والمتوفر في منصة Sinapse، ويضمن أفضل أداء في تكامل عالمي JVM وCLR.
- استرداد نوع CLR
- إنشاء مثيل لكائن CLR
- استدعاء الأساليب الثابتة
- استدعاء أساليب المثيل
- الحصول على/تعيين الخصائص الثابتة
- الحصول على/تعيين خصائص المثيل
- تعيين المندوبين
- أحداث الاشتراك/إلغاء الاشتراك
- يدمج عناصر تحكم WPF في نافذة AWT/Swing
- دمج عناصر التحكم WinForms في نافذة AWT/Swing
- دمج كائنات واجهات المستخدم الرسومية .NET المعقدة في نافذة AWT/Swing
- واجهة المستخدم الضوابط والخصائص وإدارة الأحداث
- استرداد فئة JVM
- إنشاء مثيل لكائنات JVM
- استدعاء الأساليب الثابتة
- استدعاء أساليب المثيل
- الحصول على/تعيين الحقول الثابتة
- الحصول على/تعيين حقول المثيل
- استخدم الوصول الديناميكي لكتابة التعليمات البرمجية بطريقة سلسة كما هو الحال في لغة Java
- استخدم واجهة محددة لتوجيه أساليب وحقول الإدارة
يسمح JCOBridge (JVM-CLR Object Bridge) بتنفيذ لغات JVM الأصلية، مثل java وscala، من لغات CLR/.NET والعكس، كما يسمح باستيراد واستخدام المكتبات والمكونات وأيضًا إدارة واجهة المستخدم الرسومية من واحدة. عالم البرمجة إلى الآخر. مزيد من المعلومات حول www.jcobridge.com
لاستكشاف الأمثلة، عليك تنفيذ الخطوات التالية:
من الممكن في هذا المستودع العثور على رمز مثال للغة البرمجة المختلفة التي يدعمها JCObridge. يتم تنظيم الأمثلة في مجلدين رئيسيين، JVM وCLR الذي يحتوي على المشاريع ذات الصلة. قبل تنفيذ التعليمات البرمجية، يلزم تجميع أمثلة من كلا العالمين، لأنه لا يتم تجميع التعليمات البرمجية الأجنبية في وقت التشغيل، بل يتم التنفيذ فقط.
يوضح مشروع Cross Platform GUI كيفية استخدام AWT لإنشاء واجهة مستخدم رسومية عبر الأنظمة الأساسية لـ .NET Core على مضيفي Windows وLinux. لاستخدام Swing، ما عليك سوى تغيير عناصر التحكم الموجودة داخل الكود إلى عناصر التحكم المفضلة لديك.
هذا مثال أساسي حيث نطلق على الفئة البسيطة المحددة في JavaClass.java من تطبيق .NET. في /JVM/java/src/JavaClass.java لدينا فئة بسيطة
public class JavaClass {
/**
* This simple method return the "Hello World!!" string
* * @return "Hello World!!" string
*/
public String helloWorld ()
{
return "Hello World from Java!!" ;
}
/**
* This simple method return the sum of two double
* @param a
* @param b
* @return a + b
*/
public double add ( double a , double b )
{
return a + b ;
}
/**
* This simple method return the sin of a double
* @param a
* @return sin of a
*/
public double sin ( double a )
{
return Math . sin ( a );
}
}
في CLRJavaClassUseExampleprogram.cs لدينا تطبيق .NET C# البسيط
using MASES . LicenseManager . Common ;
using MASES . JCBridge . C2JBridge ;
using System ;
namespace JavaClassUseExample
{
class Program
{
static void Main ( string [ ] args )
{
new TestClass ( ) . Execute ( ) ;
}
class TestClass : SetupJVMWrapper
{
public override string ClassPath { get { return @"....JVMOutput" ; } }
public void Execute ( )
{
double a = 2 ;
double b = 3 ;
double c = Math . PI / 2 ;
var javaClass = DynJVM . JavaClass . @new ( ) ;
string hello = javaClass . helloWorld ( ) ;
double result = javaClass . add ( a , b ) ;
double sin = javaClass . sin ( c ) ;
Console . WriteLine ( "{0} {1} + {2} = {3} and sin({4:0.0000000}) = {5:0.00000000}" , hello , a , b , result , c , sin ) ;
}
}
}
}
عند تنفيذ الكود نحصل على المخرجات التالية:
Hello World from Java!! 2 + 3 = 5 and sin(3,1415927) = 1,00000000
يعد هذا المثال امتدادًا لمثال استخدام فئة Java حيث يتم تكوين معلمات البيئة في فئة .NET TestClass .
class TestClass : SetupJVMWrapper
{
// the following line setup the classpath where JVM will search for classes
// during runtime it is possible to dynamically add other path using a call like DynJVM.JVMHelper.addPath(<the path to add>);
public override string ClassPath { get { return @"C:Program FilesMASES GroupJCOBCore;....JVMJavaOutput" ; } }
// uncomment the following line and set the correct JRE if the automatic search system fails
// public override string JVMPath { get { return @"C:Program FilesJavajre1.8.0_121binserverjvm.dll"; } }
// the following code adds all possible switch to the starting JVM.
// for a complete list see Oracle documentation: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html
public override IEnumerable < KeyValuePair < string , string > > JVMOptions
{
get
{
var dict = new Dictionary < string , string > ( ) ;
dict . Add ( "-Xmx128M" , null ) ; // this line adds a complete argument
// dict.Add(property, value); // this line adds an argument like -Dproperty = value
return dict ;
}
}
// the following code adds initial packages to the import statement.
public override IEnumerable < string > JVMPackages
{
get
{
var list = new List < string > ( ) ;
list . Add ( "java.lang" ) ; // this line adds java.lang.* like you do with "import java.lang.*" in Java
return list ;
}
}
// uncomment and set the following line when you need features of JDK like the use of the compiler
// public override string JDKHome { get { return @"C:Program FilesJavajdk1.8.0_121"; } }
public void Execute ( )
{
double a = 2 ;
double b = 3 ;
double c = Math . PI / 2 ;
var javaClass = DynJVM . JavaClass . @new ( ) ;
string hello = javaClass . helloWorld ( ) ;
double result = javaClass . add ( a , b ) ;
double sin = javaClass . sin ( c ) ;
Console . WriteLine ( "{0} {1} + {2} = {3} and sin({4:0.0000000}) = {5:0.00000000}" , hello , a , b , result , c , sin ) ;
Console . WriteLine ( "Press Enter to exit" ) ;
Console . ReadLine ( ) ;
}
}
هذا تطبيق أكثر تعقيدًا يستكشف قدرة JCOBridge على القيام بالعمليات التالية: - تنفيذ تعليمات برمجية Java في بيئة .NET باستخدام غلاف JVM الديناميكي - إدارة الكائن المشترك - تسجيل كائن CLR في جانب Java Virtual Machine - استخدم الكائن المسجل من جانب JVM - طرق الاتصال على فئة JVM المسجلة وتنعكس العملية على كائن CLR - إنشاء مربع حوار في جانب JVM واستخدامه من كود .NET
تحتوي هذه المكتبة على فئة واحدة توفر عمليات مزدوجة وسلسلة ليتم استدعاؤها من JVM.
لوحة نموذج Windows مع منطقه الكامل الذي سيتم استخدامه لتوضيح تكامل واجهة المستخدم في تطبيق Java الرسومي.
لوحة WPF مع منطقه الكامل الذي سيتم استخدامه لتوضيح تكامل واجهة المستخدم في تطبيق Java الرسومي.
هذا مثال أساسي حيث نطلق على الفئة البسيطة المحددة في CSharpClass.cs من تطبيق Java. في CLRCSharpClassCSharpClass.cs لدينا فئة بسيطة
using System ;
namespace MASES . CLRTests
{
public class CSharpClass
{
/// <summary>The method <c>HelloWorld</c> return the "Hello World!!" string</summary>
public String HelloWorld ( )
{
return "Hello World from C#!!" ;
}
/// <summary>The method <c>Add</c> return the sum of two double</summary>
public double Add ( double a , double b )
{
return a + b ;
}
/// <summary>The method <c>Add</c> return the sin of a double</summary>
public double Sin ( double a )
{
return Math . Sin ( a ) ;
}
}
}
في /JVM/src/JavaClass.java لدينا تطبيق Java البسيط
import java . io . IOException ;
import org . mases . jcobridge .*;
public class CSharpClassUseExample {
public static void main ( String [] args ) {
try {
try {
try {
JCOBridge . Initialize ( "" );
} catch ( JCException e ) {
e . printStackTrace ();
}
} catch ( IOException e ) {
e . printStackTrace ();
}
//declare and create JCOBridge instance
JCOBridge bridge ;
bridge = JCOBridge . CreateNew ();
// adds the path where extarnal assemblies where found
bridge . AddPath ( "../CLR/Output/" );
// add REFERENCES to the .dll file
bridge . AddReference ( "CSharpClass" );
// GENERATE Object
JCObject CSharpObject = ( JCObject ) bridge . NewObject ( "MASES.CLRTests.CSharpClass" );
double a = 2 ;
double b = 3 ;
double c = Math . PI / 2 ;
//Invoke the C# class methods
String hello = ( String ) CSharpObject . Invoke ( "HelloWorld" );
double result = ( double ) CSharpObject . Invoke ( "Add" , a , b );
double sin = ( double ) CSharpObject . Invoke ( "Sin" , c );
System . out . println ( String . format ( "%s %.0f + %.0f = %.0f and sin(%.8f) = %.8f" , hello , a , b , result , c , sin ));
} catch ( JCException jce ) {
jce . printStackTrace ();
System . out . println ( "Exiting" );
return ;
}
}
}
عند تنفيذ الكود نحصل على المخرجات التالية:
Hello World from C#!! 2 + 3 = 5 and sin(3,14159265) = 1,00000000
في هذا المثال الأكثر تعقيدًا، قمنا بدمج عنصري تحكم معقدين مختلفين في واجهة مستخدم awt java، مأخوذين من مكتبتين .NET. عنصر التحكم الأول هو نموذج Windows، والثاني هو كائن WPF. يعرض التطبيق الموجود في JVMJavasrcAWTWinFormsWPF.java العملية الكاملة من مرجع التحكم والإنشاء إلى تسجيل مستمع أحداث .NET إلى إدارة رد الاتصال لأحداث .NET.
import java . awt . Frame ;
import java . io . IOException ;
import org . mases . jcobridge .*;
public class AWTWinFormsWPF implements IJCVoidEventEmit {
public static void main ( String args []) {
new AWTWinFormsWPF (). createAndShow ();
}
int cycle = 0 ;
java . awt . TextArea gTextArea ;
// WPF
JCControl gControlWpfControl = null ;
// FORMS
JCControl gControlFormsControl = null ;
void createAndShow () {
try {
// LOGGER
IJCEventLog logger = null ;
try {
try {
JCOBridge . Initialize ( "" );
} catch ( JCException e ) {
e . printStackTrace ();
}
logger = new JCFileEventLog ( "WinFormsWPF.txt" );
} catch ( IOException e ) {
e . printStackTrace ();
}
JCOBridge bridge ;
bridge = JCOBridge . CreateNew ();
bridge . RegisterEventLog ( logger );
// adds the path where extarnal assemblies where found
bridge . AddPath ( "../../CLR/Output/" );
// add REFERENCES
bridge . AddReference ( "WPFTestControl" );
bridge . AddReference ( "WinFormsTestControl" );
// GENERATE CONTROLS
gControlWpfControl = bridge . GetControl ( "MASES.CLRTests.WPFTestControl.TestControl" );
gControlFormsControl = bridge . GetControl ( "MASES.CLRTests.WinFormsTestControl.TestControl" );
// CONFIGURE CONTROLS
gControlWpfControl . RegisterEventListener ( "FromComboBox" , this );
gControlWpfControl . RegisterEventListener ( "FromTextBox" , this );
gControlFormsControl . RegisterEventListener ( "FromComboBox" , this );
gControlFormsControl . RegisterEventListener ( "FromTextBox" , this );
Frame dialog = new Frame ();
gTextArea = new java . awt . TextArea ();
gTextArea . setText ( "This is an AWT TextArea" );
java . awt . GridLayout layout = new java . awt . GridLayout ( 2 , 2 );
dialog . setLayout ( layout );
dialog . add ( gControlWpfControl );
dialog . add ( gControlFormsControl );
dialog . add ( gTextArea );
dialog . validate ();
dialog . setTitle ( "WinForms-WPF AWT integration" );
dialog . setVisible ( true );
dialog . setSize ( 200 , 200 );
} catch ( JCException jce ) {
jce . printStackTrace ();
System . console (). readLine ( "Please press enter" );
System . out . println ( "Exiting" );
return ;
}
}
@ Override
public void EventRaised ( Object ... args ) {
System . out . println ( "EventRaised" );
if ( args [ 1 ] instanceof JCObject ) {
JCObject obj = ( JCObject ) args [ 1 ];
System . out . println ();
try {
if ( obj != null ) {
gTextArea . setText ( "Text area: event: " + obj . toString () + " Content: " + obj . Get ( "Content" ));
}
} catch ( JCException e ) {
e . printStackTrace ();
}
}
}
}
فئة واحدة توفر عمليات مزدوجة وسلسلة يتم استدعاؤها من .NET CLR.
فئة تحتوي على طريقتين وتعرض كيفية تسجيل واستخدام المتغيرات والكائنات العامة المشتركة
import org . mases . jcobridge .*;
import java . awt .*;
public class GlobalVariableTest
{
public static void createGlobal () throws JCException
{
Dialog dialog = new Dialog (( Dialog ) null );
JCOBridge . RegisterJVMGlobal ( "SharedDialog" , dialog );
}
public static void testMyCLRClass ( Integer a , Integer b ) throws JCException
{
JCObject resultGetCLRObject = ( JCObject ) JCOBridge . GetCLRGlobal ( "MyCLRClass" );
resultGetCLRObject . Invoke ( "Add" , a , b );
}
}
تقوم طريقة createGlobal بإنشاء مربع حوار awt عام وتسجيله لاستخدامه بسلاسة من جانب CLR. يوضح testMyCLRClass كيفية استخدام كائن CLR عام مسجل، في مثال CLR قمنا بإنشاء هذا الكائن من جانب .NET ونستدعي هذه الوظيفة لاستخدامه وإظهار أن العمليات الساخنة تنعكس بين JVM وCLR بطريقة شفافة.
يتم تعريف فئة Scala البسيطة لاستخدامها من CLR في JVMScalascalaclasssrcmainscalaScalaClass.class استدعاء تجميع وتنفيذ البرنامج النصي الدفعي في JVMScala
قبل تجميع المكالمة وتنفيذ البرنامج النصي الدفعي، يجب تثبيت ثنائيات Scala.
import java . lang . _
final class ScalaClass ( aString : String , val anInteger : Int ) {
def this () {
this ( "defaultString" , - 1 )
}
def this ( aBool : Boolean ) {
this ( "defaultString" , - 1 )
}
val scalaString = "This is a Scala String"
def add ( x : Int , y : Int ): Int = x + y
def stringConcat ( args : Array [ String ]): String =
{
return args . mkString ( ", " )
}
}
في CLRScalaClassUseExampleProgram.cs لدينا تطبيق بسيط يستخدم ScalaClass المحدد
using CommonTest ;
using MASES . JCOBridge . C2JBridge ;
using MASES . LicenseManager . Common ;
using System ;
using System . IO ;
namespace ScalaClassUseExample
{
class TestClass : BaseTestClass
{
public override string GetProjectClassPath ( )
{
#if ! JCOBRIDGE_CORE
return @"....JVMScalaOutput" ;
#else
return @"......JVMScalaOutput" ;
#endif
}
public override string ClassPath
{
get
{
return new ClassPathBuilder ( GetProjectClassPath ( ) + @"*" , @"C:Program Files (x86)scalalib*.jar" ) . Build ( ) ;
}
}
public override void Execute ( )
{
int a = 10 ;
int b = 15 ;
var scalaClass = DynJVM . ScalaClass . @new ( ) ;
var result = scalaClass . add ( a , b ) ;
Console . WriteLine ( "{0} + {1} = {2}" , a , b , result ) ;
string [ ] strings = new string [ ] { "One" , "Two" , "Three" } ;
var concatString = scalaClass . stringConcat ( strings ) ;
Console . WriteLine ( "{0} = {1}" , string . Concat ( strings ) , concatString ) ;
Console . WriteLine ( "Press Enter to exit" ) ;
Console . ReadLine ( ) ;
}
}
class Program
{
static void Main ( string [ ] args )
{
try
{
new TestClass ( ) . Execute ( ) ;
}
catch ( Exception e )
{
Console . WriteLine ( e . Message ) ;
Console . WriteLine ( "Press any key." ) ;
Console . ReadKey ( ) ;
}
}
}
}
في Scala، يجب إضافة جميع المكتبات المطلوبة بشكل صريح إلى المسار الأساسي.
في هذا المثال نقوم باستدعاء كائن .NET من لغة Scala عبر JCOBridge. قبل تجميع المكالمة وتنفيذ البرنامج النصي الدفعي، يجب تثبيت ثنائيات Scala.
import java . util . Iterator
import org . mases . jcobridge . _
object Main extends App {
try
{
JCOBridge . Initialize ();
}
catch
{
// catch to avoid problem with Trial mode of JCOBridge
case jce : JCException => System . out . println ( jce . getMessage )
}
val bridge = JCOBridge . CreateNew ()
// adds a new reference to WPF
bridge . AddReference ( "PresentationFramework" )
// get MessageBox type
val msgType = bridge . GetType ( "System.Windows.MessageBox" )
// invoke static method to show a message box on the screen
msgType . Invoke ( "Show" , "Please press enter to continue" )
// get .NET type
val enumType = bridge . GetType ( "System.Environment" )
// invokes static method
val genObj = enumType . Invoke ( "GetLogicalDrives" )
// retrieve the iterator
val iteratorObj = genObj . asInstanceOf [ JCObject ]. iterator
// iterate on all object and print the value
while ( iteratorObj . hasNext ) println ( iteratorObj . next )
// invoke static method to show a message box on the screen
msgType . Invoke ( "Show" , "Please press enter" )
// event callback example
val tObj = bridge . NewObject ( "System.Timers.Timer" ); // create the timer object
val timerObj = tObj . asInstanceOf [ JCObject ];
// register an event handler when the Timer elaps
timerObj . RegisterEventListener ( "Elapsed" , new ScalaJCVoidEventEmit ());
// set Interval property
timerObj . Set ( "Interval" , 1000 ); // set properties
// enable the Timer
timerObj . Set ( "Enabled" , true ); // start timer
// invoke static method to show a message box on the screen
msgType . Invoke ( "Show" , "Please press enter" )
}
final class ScalaJCVoidEventEmit () extends JCVoidEventEmit {
override def EventRaised ( args : Object *) : Unit =
{
// scala seems to have a problem to translate var args argument into JVM bytecode. This method is needed to avoid compilation problems
}
// this method defines exactly the signature expected from the event
def EventRaised ( sender : Object , arg : Object ) : Unit =
{
println ( "Timer Elapsed" )
}
}