I am using py4j for communication between python and java.I am able to call python method from java side. But from python I am not able to send any object or call java method. Here is the code i have tried.
My java code:
public interface IHello {
public String sayHello();
public String sayHello(int i, String s);
// public String frompython();
}
//ExampleClientApplication.java
package py4j.examples;
import py4j.GatewayServer;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class ExampleClientApplication extends Thread {
public void run(){
System.out.println("thread is running...");
}
public static void main(String[] args) {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
GatewayServer.turnLoggingOff();
GatewayServer server = new GatewayServer();
server.start();
IHello hello = (IHello) server.getPythonServerEntryPoint(new Class[] { IHello.class });
try {
System.out.println("Please enter a string");
String str = br.readLine();
System.out.println(hello.sayHello(1, str));
} catch (Exception e) {
e.printStackTrace();
}
ExampleClientApplication t1 = new ExampleClientApplication();
t1.start();
//server.shutdown();
}
}
My python code :
class SimpleHello(object):
def sayHello(self, int_value=None, string_value=None):
print(int_value, string_value)
return "From python to {0}".format(string_value)
class Java:
implements = ["py4j.examples.IHello"]
# Make sure that the python code is started first.
# Then execute: java -cp py4j.jar
py4j.examples.SingleThreadClientApplication
from py4j.java_gateway import JavaGateway, CallbackServerParameters
simple_hello = SimpleHello()
gateway = JavaGateway(
callback_server_parameters=CallbackServerParameters(),
python_server_entry_point=simple_hello)
The send objects problem is easily solved by implementing a getter/eval method in the java interface that is implemented by python, which can then be called from java to get the variable that is requested. For an example have a look at the py4j implementation here: https://github.com/subes/invesdwin-context-python
Specifically see the get/eval method implementation here: https://github.com/subes/invesdwin-context-python/blob/master/invesdwin-context-python-parent/invesdwin-context-python-runtime-py4j/src/main/java/de/invesdwin/context/python/runtime/py4j/pool/internal/Py4jInterpreter.py
For the other way around, you would have to do same on the java gateway class and provide a get/eval method that can be called from python. The actual java code could be executed in a ScriptEngine for groovy and the result could be returned to python. (see http://docs.groovy-lang.org/1.8.9/html/groovy-jdk/javax/script/ScriptEngine.html)
Though it might be a better idea to decide about a master/slave role and only once input the parameters, then execute the code in python and retrieve the results once. Or the other way around if python should be leading. Thus you would reduce the communication overhead a lot. For a tighter integration without as much of a performance penalty as py4j incurs, you should have a look at https://github.com/mrj0/jep to directly load the python lib into the java process. Then each call is not as expensive anymore.
Related
This question already has answers here:
How do I create a file and write to it?
(35 answers)
Closed 3 years ago.
I want to create a java program that generates another java class in the same project. For example in the class Dragon.java, i want to write java code that creates another java class called fire.java. I do not want to use any GUI from eclipse, just pure code that generates another class from the execution of written programming in java.
I have tried making objects of a non existent class in hopes of the program automatically producing a class with that name.
Again, it doesn't have to be just a java class, is there a way to make other forms of files also? for example fol.flow, or of different names.
Creating a new Java file is easy. You can use any FileWriter technique. But what need to be taken care of is that new Java file is valid java file and can be compiled to class file.
This link has working example of doing the same.
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
public class MakeTodayClass {
Date today = new Date();
String todayMillis = Long.toString(today.getTime());
String todayClass = "z_" + todayMillis;
String todaySource = todayClass + ".java";
public static void main (String args[]){
MakeTodayClass mtc = new MakeTodayClass();
mtc.createIt();
if (mtc.compileIt()) {
System.out.println("Running " + mtc.todayClass + ":\n\n");
mtc.runIt();
}
else
System.out.println(mtc.todaySource + " is bad.");
}
public void createIt() {
try {
FileWriter aWriter = new FileWriter(todaySource, true);
aWriter.write("public class "+ todayClass + "{");
aWriter.write(" public void doit() {");
aWriter.write(" System.out.println(\""+todayMillis+"\");");
aWriter.write(" }}\n");
aWriter.flush();
aWriter.close();
}
catch(Exception e){
e.printStackTrace();
}
}
public boolean compileIt() {
String [] source = { new String(todaySource)};
ByteArrayOutputStream baos= new ByteArrayOutputStream();
new sun.tools.javac.Main(baos,source[0]).compile(source);
// if using JDK >= 1.3 then use
// public static int com.sun.tools.javac.Main.compile(source);
return (baos.toString().indexOf("error")==-1);
}
public void runIt() {
try {
Class params[] = {};
Object paramsObj[] = {};
Class thisClass = Class.forName(todayClass);
Object iClass = thisClass.newInstance();
Method thisMethod = thisClass.getDeclaredMethod("doit", params);
thisMethod.invoke(iClass, paramsObj);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
At first I thought you wanted code generation, but you simply want to write to files or create them?
The simplest code to create file and write to it:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class Testing {
public static void main(String[] args) throws IOException {
Files.writeString(Paths.get("D://output.txt"), "some text to write", StandardOpenOption.CREATE);
}
}
It uses only java standard classes, you don't need any libraries or anything external. Just make sure to write to the valid path, where you have access.
If you want to generate files with java code, you can just do it with the method above, but creating the String with code content is really hard, there are libraries for it and they are not easy to use for beginners. For example javapoet. I personally used javaparser, it has a lot of other possibilities besides generating code.
I need to reference a .Net dll in java. I have used jni4net libraries for the same. I have followed the steps mentioned in the video below :
https://www.youtube.com/watch?time_continue=351&v=8OoSK_RWUe4
I have followed all the steps required to reference jni4net libraries but i get the following runtime Exception:
Exception in thread "main" java.lang.UnsatisfiedLinkError: orionforpython.DynamicOrion.__ctorDynamicOrion0(Lnet/sf/jni4net/inj/IClrProxy;)V
at orionforpython.DynamicOrion.__ctorDynamicOrion0(Native Method)
at orionforpython.DynamicOrion.<init>(DynamicOrion.java:25)
at com.orion.OrionForJava.main(OrionForJava.java:16)
After following all the steps, This is my code:
package com.orion;
import net.sf.jni4net.Bridge;
import orionforpython.*;
import java.io.*;
class OrionForJava {
public static void main(String[] args) throws IOException {
Bridge.setVerbose(true);
Bridge.init();
File proxyAssemblyFile=new File("OrionForPython.dll");
Bridge.LoadAndRegisterAssemblyFrom(proxyAssemblyFile);
DynamicOrion orion=new DynamicOrion();
String res=orion.ReqLogin("user", "pwd", "");
System.out.print(res);
}}
I have tried executing the same using NetBeans 8.1 IDE but with no success. I am using jni4net-0.8.8.0 version and Eclipse IDE for Java Developers
Version: Oxygen.3 Release (4.7.3)
Any assistance would be helpful!
I used jni4net library to call c# dlls from java and it is working fine. I used a lightly different approach to initialize jni4net.
try {
Bridge.setVerbose(true);
Bridge.init(new File("Full path to jni4net.n.w64.v40-0.8.8.0.dll"));
// where dlls to load is jni4net.n.w64.v40-0.8.8.0.dll,jni4net.n-0.8.8.0.dll,MyOriginalNETDll.dll,MyOriginalNETDll.j4n.dll (after proxygen processing)
for (String str : dllsToLoad) {
File dll = new File(rutaDlls + str);
Bridge.LoadAndRegisterAssemblyFrom(dll);
}
} catch (IOException e) {
LOG.error("Error jniBrige.", e);
}
I needed to use full path c:... to the dll to make it work. I also had to take care about .net framework version used to create assembly (need to use 4.0 in my case and java version 8)
Hopes this helps
We use JCOBridge which can be used in .NET Core (>= 3.1), .NET 5/6 and .NET Framework (>= 4.6.1). Referencing the DLL you need to call you will have full access to it and you can use it in your projects.
Consider the following C# snippet class available in a generic TestBridge.dll:
using System;
namespace TestBridge
{
public class MyClass
{
/// <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);
}
}
}
The methods of the previous class can be invoked from the following java code snippet:
import java.io.IOException;
import org.mases.jcobridge.*;
public class CSharpClassUse {
public static void main(String[] args) {
try {
try {
try {
JCOBridge.Initialize();
} catch (JCException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
return;
}
//declare and create JCOBridge instance
JCOBridge bridge;
bridge = JCOBridge.CreateNew();
// adds the path where external assemblies can be found
bridge.AddPath("Path where is TestBridge.dll assembly");
// add REFERENCES to the .dll file you want to invoke
bridge.AddReference("TestBridge.dll");
// INSTANTIATE the .NET Object: JCObject is a meta object
JCObject theNetClassInstance = (JCObject) bridge.NewObject("TestBridge.MyClass");
double a = 2;
double b = 3;
double c = Math.PI/2;
//Invoke the C# class methods
String hello = (String) theNetClassInstance.Invoke("HelloWorld");
double result = (double) theNetClassInstance.Invoke("Add", a, b);
double sin = (double) theNetClassInstance.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;
}
}
}
The previous java code produces the following output:
Hello World from C#!! 2 + 3 = 5 and sin(3,14159265) = 1,00000000
The previous example shown how use a C# class available in a DLL. If you need to invoke/integrate .NET graphic, that in generic sense are C# DLL too, JCOBridge also manages GUI integration (WPF/WinForms/AWT/Swing): look at these Examples
Hope it was useful and clear.
I am new to accessing DLLs from Java using JNA. I need to access methods from a class within a DLL(written in .net). Form this sample DLL below, I am trying to get AuditID and Server ID. I am ending with the following error while I am running my code. Any guidance really appreciated.
/// Error ///
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'GetEnrollcontext': The specified procedure could not be found.
//DLL File Code//
SampleDLL.ProfileEnroll enrollcontext = new SampleDLL.ProfileEnroll();
enrollcontext.Url =” url”;
enrollcontext.AuditIdType = SampleDLL.ProfileId;
enrollcontext.AuditId = “22222222 “;
enrollcontext.ServerId = “server1”;
/// Java Code ///
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Structure;
import dllExtract.DLLExtractTest.SampleDLL.Enrollcontext;
public class SampleDLLExtract {
public interface SampleDLL extends Library {
SampleDLL INSTANCE = (SampleDLL) Native.loadLibrary("SampleDLL",
SampleDLL.class);
public static class Enrollcontext extends Structure {
public String auditId;
public String serverId;
}
void GetEnrollcontext(Enrollcontext ec); // void ();
}
public static void main(String[] args) {
SampleDLL sdll = SampleDLL.INSTANCE;
SampleDLL.Enrollcontext enrollContext = new SampleDLL.Enrollcontext();
sdll.GetEnrollcontext(enrollContext);
System.out.println(sdll.toString(sdll.GetEnrollcontext(enrollContext)));
}
}
in fact there is a solution for you to use C#, VB.NET or F# code via JNA in Java (and nothing else)! and it is also very easy to use:
https://www.nuget.org/packages/UnmanagedExports
with this package all you need to do is, add [RGiesecke.DllExport.DllExport] to your methods like that:
C# .dll Project:
[RGiesecke.DllExport.DllExport]
public static String yourFunction(String yourParameter)
{
return "CSharp String";
}
Java Project:
public interface jna extends Library {
jna INSTANCE = (jna) Native.loadLibrary("yourCSharpProject.dll", jna.class);
public String yourFunction(String yourParameter);
}
use it in the code:
System.out.println(jna.INSTANCE.yourFunction("nothingImportant"));
Viola!
As already mentioned it works very easy, but this solution has some limitations:
only available for simple datatypes as parameter & return values
no MethodOverloading available. yourFunction(String yourParameter) and yourFunction(String yourParameter, String yourSecondParameter) does not work! you have to name them differently
Use arrays as parameter or return values. (JNA offers StringArray, but I am not able to use them in C#) (maybe there is a solution, but I couldn't come up with one so far!)
if you export a method you can't call it internally in your C# code (simple to bypass that by the following:
.
[RGiesecke.DllExport.DllExport]
public static Boolean externalAvailable(String yourParameter)
{
return yourInternalFunction(yourParameter);
}
With C# it works great, with VB.NET and F# I have no experience.
hope this helps!
I am using JPachube.jar and Matlab in order to send data to my datastream. This java code works on my machine:
package smartclassroom;
import Pachube.Data;
import Pachube.Feed;
//import Pachube.FeedFactory;
import Pachube.Pachube;
import Pachube.PachubeException;
public class SendFeed {
public static void main(String arsg[]) throws InterruptedException{
SendFeed s = new SendFeed(0.0);
s.setZainteresovanost(0.3);
double output = s.getZainteresovanost();
System.out.println("zainteresovanost " + output);
try {
Pachube p = new Pachube("MYAPIKEY");
Feed f = p.getFeed(MYFEED);
f.updateDatastream(0, output);
} catch (PachubeException e) {
System.out.println(e.errorMessage);
}
}
private double zainteresovanost;
public SendFeed(double vrednost) {
zainteresovanost = vrednost;
}
public void setZainteresovanost(double vrednost) {
zainteresovanost = vrednost;
}
public double getZainteresovanost() {
return zainteresovanost;
}
}
but I need to do this from Matlab. I have tried rewriting example (example from link is working on my machine): I have compile java class with javac and added JPachube.jar and SendFeed.class into path and then utilize this code in Matlab:
javaaddpath('C:\work')
javaMethod('main','SendFeed','');
pachubeValue = SendFeed(0.42);
I get an error:
??? Error using ==> javaMethod
No class SendFeed can be located on Java class path
Error in ==> post_to_pachube2 at 6
javaMethod('main','SendFeed','');
This is strange because, as I said example from the link is working.
Afterwards, I decided to include JPachube directly in Matlab code and to write equivalent code in Matlab:
javaaddpath('c:\work\JPachube.jar')
import Pachube.Data.*
import Pachube.Feed.*
import Pachube.Pachube.*
import Pachube.PachubeException.*
pachube = Pachube.Pachube('MYAPIKEY');
feed = pachube.getFeed(MYFEED);
feed.updateDatastream(0, 0.54);
And I get this error:
??? No method 'updateDatastream' with matching signature found for class 'Pachube.Feed'.
Error in ==> post_to_pachube2 at 12
feed.updateDatastream(0, 0.54);
So I have tried almost everything and nothing! Any method making this work will be fine for me. Thanks for help in advance!
This done trick for me (answer from here)
javaaddpath('c:\work\httpcore-4.2.2.jar');
javaaddpath('c:\work\httpclient-4.2.3.jar');
import org.apache.http.impl.client.DefaultHttpClient
import org.apache.http.client.methods.HttpPost
import org.apache.http.entity.StringEntity
httpclient = DefaultHttpClient();
httppost = HttpPost('http://api.cosm.com/v2/feeds/FEEDID/datastreams/0.csv?_method=put');
httppost.addHeader('Content-Type','text/plain');
httppost.addHeader('X-ApiKey','APIKEY');
params = StringEntity('0.7');
httppost.setEntity(params);
response = httpclient.execute(httppost);
I would rather use built-in methods. Matlab hasurlread/urlwrite, which could work if all you wish to do is request some CSV data from Cosm API. If you do need to use JSON, it can be handled in Matlab via a plugin.
Passissing the Cosm API key, that can be done via key parameter like so:
cosm_feed_url = "https://api.cosm.com/v2/feeds/61916.csv?key=<API_KEY>"
cosm_feed_csv = urlread(cosm_feed_url)
However, the standard library methods urlread/urlwrite are rather limited. In fact, the urlwrite function is only designed for file input, and I cannot even see any official example of how one could use a formatted string instead. Creating a temporary file would reasonable, unless it's only a few lines of CSV.
You will probably need to use urlread2 for anything more serious.
UPDATE: it appears that urlread2 can be problematic.
I'm not really sure how I can explain this, but here goes:
I want to be able to "insert" some commands into parts of my code which will be loaded from external files. To parse and execute these commands, I presumably have to use some scripting like BeanShell's eval method. The problem is that it doesn't seem to recognize the instance/method it's inside of. As a very basic example, I want to do something like
public void somethingHappens()
{
Foo foo = new Foo();
Interpreter i = new Interpreter();
i.eval("print(foo.getName());");
}
Is this possible? Should I use other scripting tools?
If you're using 1.6, you can use the built in JavaScript support.
The Java Scripting Programmer's Guide explains how to import Java classes into your script.
Code example 9 in this article explains how to pass objects into the script's scope.
Using beanshell, this is something you can try
package beanshell;
import bsh.EvalError;
import bsh.Interpreter;
public class DemoExample {
public static void main( String [] args ) throws EvalError {
Interpreter i = new bsh.Interpreter();
String usrIp = "if(\"abc\".equals(\"abc\")){"
+ "demoExmp.printValue(\"Rohit\");"
+ "}";
i.eval(""
+ "import beanshell.DemoExample;"
+ "DemoExample demoExmp = new beanshell.DemoExample();"
+ ""+usrIp);
}
public static void printValue(String strVal){
System.out.println("Printing Value "+strVal);
}
}