I am working on a project that uses Java, C# and also C++ applications. To communicate between them I am trying to use Google protocol buffer. I am using following .proto file, which was taken from examples:
package tutorial;
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
message AddressBook {
repeated Person person = 1;
}
I am referring to following tutorial:
https://developers.google.com/protocol-buffers/docs/csharptutorial
Tutorials for other languages are also there.
I tried following command line arguments for each language:
Java:
C:\ProtoBuf\protoc -I=C:\trash --java_out=C:\trash C:\trash/addressbook.proto
C++:
C:\ProtoBuf\protoc -I=C:\trash --cpp_out=C:\trash C:\trash/addressbook.proto
C#:
C:\ProtoBuf\protoc -I=C:\trash --csharp_out=C:\trash C:\trash/addressbook.proto
Java and C++ compilations work properly even with some warning in case of Java. But I get following output with C# :
--csharp_out: protoc-gen-csharp: The system cannot find the file specified.
I am using this compiler: https://github.com/google/protobuf/releases/download/v2.6.1/protoc-2.6.1-win32.zip
What am I doing wrong here? do I need any other files for C# compilation?
You are trying to generate C# files using the old version of the protoc
protoc-2.6.1-win32.zip
C# code generator for both proto2 and proto3 was introduced only in Version 3.0.0-alpha-3
Introduced two new language implementations (Objective-C, C#) to
proto3.
So, download protoc Version 3.0.0-alpha-3, install it and call:
protoc -I=$SRC_DIR --csharp_out=$DST_DIR $SRC_DIR/your.proto
Beware that started from Version 3.0.0-beta-1 C# code generator only supports generating proto3:
Proto3 semantics supported; proto2 files are prohibited for C# codegen
I know how to gen proto files in c#
open visual studio, open nuget command line, type : Install-Package Google.ProtocolBuffers , link : Google.ProtocolBuffers 2.4.1.555
find Package/Google.ProtocolBuffers.2.4.1.555/tools/ProtoGen.exe
use command line, type : ProtoGen.exe addressbook.proto -output_directory=C:\trash
I write a python script to gen proto files, gen.py
import os, subprocess, threading
def main():
with open("conf.txt") as file:
exe = os.path.join(os.getcwd(), "..\\Package\\Google.ProtocolBuffers.2.4.1.555\\tools\\ProtoGen.exe")
out = "-output_directory=%s" % (os.path.join(os.getcwd(), "..\\Common\\libs\\protos"))
def gen(proto):
subprocess.check_call([exe, os.path.join("protos", proto), out])
list = []
for proto in file.read().split(','):
t = threading.Thread(target = gen, args = (proto, ))
t.start()
list.append(t)
for t in list:
t.join()
if __name__ == '__main__':
main()
conf.txt
base.proto,test.proto,addressbook.proto
I solved all my problems using / (slash) intead of \ (anti-slash) in all the path.
protoc.exe -I=D:/dev/xyz/projects --csharp_out=d:/temp D:/dev/xyz/projects/messages.proto
Related
i start whith gRPC bulding an easy Java Chat Programm.
protc --version prints libprotoc 3.5.1
the -proto File:
syntax = "proto3";
option java_multiple_files = true;
option java_package = "grpc";
// whihout this Option i get no service
option java_generic_services = true;
option java_outer_classname = "ChatProto";
option objc_class_prefix = "HLW";
package chat;
message ClientPost {
string name = 1;
string value = 2;
}
message ServerReply {
ClientPost back = 1;
}
// The service definition.
service Verbindung {
rpc ChatService (stream ClientPost) returns (stream ServerReply);
}
// file end
why i need to set the option java_generic_services ?
class ChatImpl extends grpc.Verbindung {
#Override
public void chatService(RpcController controller, ClientPost request, RpcCallback done) {
// why i get this kind of Service ?
}
}
//
2. why i get an other class name ? shut be VerbindungImplBase
expected Function
public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) { }
what must i do to get this kind of expected Service Function ?
may be an wrong protoc compiler / wrong Installation / missing Parts ?
You're likely not running the gRPC code generator. Without the full configuration of how you're running protoc I can't point out too much detail, but you are likely only generating the protobuf messages via java_generic_services=true.
You shouldn't need java_generic_services=true. Instead, you should generate the messages like you are now, but then also use the grpc-java plugin. There's documentation for when running protoc manually and our main documentation documents the preferred method, using Maven or Gradle plugins.
I have an open suse leap 42.2 System
this Version knows nothing about grpc - no Support from this side
i get the compiled protoc - it comes whithout the needed Java-gen Plugin
found https://github.com/grpc/grpc-java/blob/master/compiler/README.md
"Normally you don't need to compile the codegen by yourself, since pre-compiled binaries for common platforms are available on Maven Central."
i found only some exe files. - not useful
"Change to the compiler directory:"
i have no compiler dir. - still try to find out were i can get
NetBeans have only an Editor plugin for protofiles - so my IDE can't handel gRPC
maybe for other IDEs are the Maven Plugins for gRPC are helpful
i expected an full protoc Compiler with all needed plugins :-)
not an install the tool adventure.
a the Moment for me: gRPC - nice Idea , but i get an "install the gRPC" Adventure
I've the following .proto file:
message MediatorMessageMsg{
required double speed = 1;
required double heading = 2;
required string sender = 3;
}
and I use Eclipse Mars with Protocol Buffer 2.5.0 version. It generates the necessary file (which we are not supposed to edit) however I cannot use the important functions of
writeDelimitedTo()
parseDelimitedFrom()
newBuilder().set...
without these there is simply no point in using the entire thing. I checked the file and I can see parseDelimitedFrom() there, however I cannot call it in my own project (Yes, imported already). When I hover my mouse on the error, it gives me the following:
The method parseDelimitedFrom(ByteArrayInputStream) is undefined for the type MediatorMessage
Anyone has an idea why is this the case?
EDIT: Some more details regarding the question.
I cannot use the function below, for instance, to build my message. It raises an error.
MediatorMessage mediatorMessage = MediatorMessage.newBuilder().
or I cannot do this
ByteArrayOutputStream output = new ByteArrayOutputStream(bufferSize);
mediatorMessage.writeDelimitedTo(output);
or this
ByteArrayInputStream firstInput = new ByteArrayInputStream(buf);
mediatorMessageOne = MediatorMessage.parseDelimitedFrom(firstInput);
So these functions are not recognized for some reason.
As you still have not answered how your MediatorMessageMsg from the *.proto file becomes MediatorMessage.java find below a stripped down example. Which should point you in the right direction.
Assume following directory and file structure, protoc is assumed to be installed and in your PATH.
bin/
lib/protobuf-java-2.5.0.jar
src/Check.java
MediatorMessage.proto
src/Check.java
import com.google.protobuf.TextFormat;
import sub.optimal.MediatorMessage.MediatorMessageMsg;
class Check {
public static void main(String...args) {
MediatorMessageMsg.Builder builder = MediatorMessageMsg.newBuilder();
MediatorMessageMsg msg = builder.setSpeed(42.0)
.setHeading(0.0)
.setSender("foobar")
.build();
System.out.println(TextFormat.shortDebugString(msg));
}
}
MediatorMessage.proto
option java_package = "sub.optimal";
option java_outer_classname = "MediatorMessage";
message MediatorMessageMsg{
required double speed = 1;
required double heading = 2;
required string sender = 3;
}
generate Java source from proto file
protoc --java_out=src/ MediatorMessage.proto
this generates the Java source file src/sub/optimal/MediatorMessage.java.
compile the Java sources
javac -cp lib/protobuf-java-2.5.0.jar:src/. -d bin/ src/Check.java
this generates the files
bin/Check.class
bin/sub/optimal/MediatorMessage$1.class
bin/sub/optimal/MediatorMessage$MediatorMessageMsg$1.class
bin/sub/optimal/MediatorMessage$MediatorMessageMsg$Builder.class
bin/sub/optimal/MediatorMessage$MediatorMessageMsg.class
bin/sub/optimal/MediatorMessage$MediatorMessageMsgOrBuilder.class
bin/sub/optimal/MediatorMessage.class
run the simple check
java -cp lib/protobuf-java-2.5.0.jar:bin/ Check
output
speed: 42.0 heading: 0.0 sender: "foobar"
I am using weka api through c#. I have converted weka jar file to c# dll by using ikvm. Then I have added the converted dll (wekacsharp.dll) in my reference.
I have also added ikvm.gnu.classpath.dll, IKVM.OpenJDK.Core.dll, IKVM.OpenJDK.Util.dll, IKVM.OpenJDK.Text.dll, IKVM.OpenJDK.Core in my reference.
I am trying to use j48 algorithm but i am getting the error. Screen shot of code error is attached. Kindly check it and suggest me something to fix it.
Code:
public static void classifyTest()
{
try
{
weka.core.Instances insts = new weka.core.Instances(new java.io.FileReader("iris.arff"));
insts.setClassIndex(insts.numAttributes() - 1);
weka.classifiers.Classifier cl = new weka.classifiers.trees.J48();
//Console.WriteLine("Performing " + percentSplit + "% split evaluation.");
//randomize the order of the instances in the dataset.
// weka.filters.Filter myRandom = new weka.filters.unsupervised.instance.Randomize();
// myRandom.setInputFormat(insts);
// insts = weka.filters.Filter.useFilter(insts, myRandom);
int trainSize = insts.numInstances() * percentSplit / 100;
int testSize = insts.numInstances() - trainSize;
weka.core.Instances train = new weka.core.Instances(insts, 0, trainSize);
cl.buildClassifier(train);
int numCorrect = 0;
for (int i = trainSize; i < insts.numInstances(); i++)
{
weka.core.Instance currentInst = insts.instance(i);
double predictedClass = cl.classifyInstance(currentInst);
if (predictedClass == insts.instance(i).classValue())
numCorrect++;
}
//java.io.Console.WriteLine(numCorrect + " out of " + testSize + " correct (" +(double)((double)numCorrect / (double)testSize * 100.0) + "%)");
}
catch (java.lang.Exception ex)
{
ex.printStackTrace();
}
}
Make sure that you did not skip the conversion of the weka.jar to weka.dll using Ikvm before adding it as a reference to your C# project.
Conversion from Java to a .NET dll
With that out of the way, the first thing you will want to do is to convert the Weka .jar file into a .NET dll. To do this, we will use ikvmc, which is the IKVM static compiler.
On the console, go to the directory which contains weka.jar, and type:
ikvmc -target:library weka.jar
The -target:library call causes ikvmc to create a .dll library instead of an executable.
Note that the IKVM tutorial tells you that you should add
-reference:/usr/lib/IKVM.GNU.Classpath.dll
(or appropriate path) to the above command, it tells IKVM where to find the GNU Classpath library. However, IKVM.GNU.Classpath.dll is no longer included in the download package, and is from very old versions of IKVM. When Sun open sourced Java, it got replaced by the IKVM.OpenJDK.*.dll files.
You should now have a file called "weka.dll", which is a .NET version of the entire weka API. That's exactly what we want!
Use the dll in a .NET application
To try it out, let's use a small C# program that I wrote. The program simply runs the J48 classifier on the Iris dataset with a 66% test/data split, and prints out the correctness percentage. It also uses a few Java classes, and is already about 95% legal Java code.
I am trying to generate java files from below proto file using protobuf nano. I got some basic instruction on how to proceed in this SO thread.
I have this proto file, personal.proto:
package tutorial;
option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos";
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
message AddressBook {
repeated Person person = 1;
}
I tried to follow the instruction from here, more specifically NANO version:
Downloaded protobuf-2.5.0.zip and compiler protoc-2.5.0-win32.zip from here.
Unzipped protobuf-2.5.0.zip to a folder and in there in src subfolder I unzipped protoc.exe.
Changed to java folder and in there issued: mvn clean package -P nano. That command ran fine and in target folder I have protobuf-java-2.5.0.jar
From here I am not sure how to proceed since in the initial documentation I have this statement:
- Link with the generated jar file
<protobuf-root>java/target/protobuf-java-2.3.0-nano.jar.
I am not sure what that means, how to link? Is there some parameter for protoc.exe that specifies the jar file to use?
I tried to issue this command: protoc --javanano_out=enum_style=java --java_out=generated personal.proto
but I get this error: --javanano_out: protoc-gen-javanano: The system cannot find the file specified.
The question would be: what am I missing/doing wrong above? I am trying to generate java files from above proto file.
I think this protoc is not compiled with javanano support.
The pre-compiled windows version 2.5.0 does not include nano support, take a look at the source code, in the "src\google\protobuf\compiler" path, includes the java generator but not the javanano generator. The latest source code at google repositories includes javanano.
You can download the latest source code and try to compile it using MinGW and msys or CygWin, take a look at this post How to build google protocol buffers in Windows for mingw?
(I will post details for the building process later)
UPDATE:
The final command line after building protoc.exe
For one proto file
protoc --javanano_out=store_unknown_fields=true:target/generated-sources personal.proto, target/generated-sources
For multiple proto files
protoc --javanano_out=store_unknown_fields=true:target/generated-sources --proto_path=inputpath input/*.proto
EDIT Nano generator replaces enum members with public static final int fields. This is a problem if a class has an optional enum member because that member will be compiled to a primitive int value and will take the default value of zero, which will be the first element from enum. To distinguish the cases when an enum value was not set, one can take advantage of optional_field_style parameter that will generate java.lang.Integer instead of a primitive int. When the proto is parsed, the caller can check if the value is null before using the value. Null means the value was not set.
The above call script can become:
protoc --javanano_out=store_unknown_fields=true,optional_field_style=reftypes:target/generated-sources --proto_path=input input/*.proto
I am trying to access a device through a COM object in a JAVA interface.
The particular call (as described by the manufacturer) is:
Name: ScanUSB
Parameters: [out] VARIANT* serialNumbers
Use: serialNumbers is a pointer to a VARIANT containing an array of BSTR.
The exact call doesn't matter, but I need to feed it a BSTR array through the Java interface. A VB demo for the COM interface simply does this with the commandlm_Co1.ScanUSB(snNum), with Dim snNum As Object = Nothing. The Items in snNum are then displayed in a dropdown menu.
I am trying to do this with JACOB, as I have had the most luck with communication. This is more or less what I am using:
import com.jacob.com.Variant;
import com.jacob.com.Dispatch;
public class JunoReader {
public JunoReader() {
Dispatch oOphirLink = new Dispatch("clsid:{--the id of the device here--}");
Variant snNum = new Variant();
Variant testing = Dispatch.call(oOphirLink,"ScanUSB", snNum);
println(testing);
}
}
When I run this, everything compiles properly and I can confirm that I am communicating with the device, but all I get back is the null Variant that I put in.
My question is: How can I feed a BSTR array to a COM object through a JAVA interface?
Thanks!
So, one month and zero free time later, I have an answer to my own question and that answer is "Use Python".
Python allows users to access COM objects with the comtypes module, effectively with a single command:
from comtypes.client import CreateObject
target_guid = CreateObject("{TARGET-COM-CLSID-HERE}")
This allows python to talk with whatever the COM object is, so there was none of the trouble that Java was giving me. The single line: target_guid.ScanUSB() produced (u'717610',), the serial number of the target device. Notice that Python has no trouble reading the Unicode produced by the COM object.
The second trick involves Python's COM server, generated with the win32com module. Because the COM servers can be registered to Windows, I don't have to worry about where the dll is located. All I need is the clsid. To build the python COM server, I followed the instructions for a "quick start to server side COM and Python". So what does it all look like?
Python code:
class OphirPyCOM:
_reg_clsid_ = "{PYTHON-COM-CLSID-HERE}"
_reg_desc_ = "Python COM server"
_reg_progid_ = "Python COM server"
_public_methods_ = [ 'Hello',
'ConnectOphir',
'ScanUSB', """More methods here"""
]
_public_attrs_ = ["""Some public attributes"""]
_readonly_attrs_ = ["""some read-only attributes"""]
def __init__(self):
"""some variables declared here"""
def Hello(self, who):
"""Verifies a connection"""
return "{PYTHON-COM-CLSID-HERE}" + str(who)
def ConnectOphir(self,clsid):
"""Connects to the target COM Object"""
from comtypes.client import CreateObject
self.target_guid = CreateObject(clsid)
return "OphirLMMeasurement object created."
def ScanUSB(self):
"""Communicates with the target device"""
self.connected_inst = self.target_guid.ScanUSB()
for i in range(0,len(self.connected_inst)):
self.inst_list.append(str(self.connected_inst[i]))
return self.inst_list
if __name__ == "__main__":
# use 'python com.py' to register the COM server
# use 'python com.py --unregister' to unregister it
print "Registering COM server..."
import win32com.server.register
win32com.server.register.UseCommandLine(OphirPyCOM)
We can run that with the command line and get it registered. Then we take the values over to Java with JACOB:
import com.jacob.com.Variant;
import com.jacob.com.Dispatch;
public class JunoReader {
String pyClsid = "{PYTHON-COM-CLSID-HERE}"; // This is where your python COM clsid goes
String opClsid = "{TARGET-COM-CLSID-HERE}"; // This is where your ultimate target clsid goes
public JunoReader() {
_pyClsid = "clsid:" + pyClsid
// This finds the COM object location:
Dispatch oOphirLink = new Dispatch(_pyClsid);
}
public String HandShake() {
String _talkBack = "is connected.";
Variant _handShake = Dispatch.call(oOphirLink,"Hello",_talkBack); // I am trying to look for the Juno...
return (_handShake.toString());
}
public String ConnectOphir() {
Variant _connectOphir = Dispatch.call(oOphirLink,"ConnectOphir", opClsid); // Connect to the target COM object
return (_connectOphir.toString());
}
public String ScanUSB() {
Variant _serialNumberList = Dispatch.call(oOphirLink,"ScanUSB"); // This scans the USB ports for devices
return (_serialNumberList.toString());
}
}
calling JunoReader.ScanUSB() produces: 717610, exactly like it is supposed to. Implementing the subsequent methods of the manufacturer dll allowed me to read data from this device into a Java applet. Problem solved.
A caveat: you may need to unregister the Python COM every time you change the change the source file and then re-register with a different clsid. Java was having a tough time establishing a connection to the updated code unless I used a new clsid every time I changed the file.
Why did I spend all this time typing this up? Because most of the advice related to reading native data types into Java involved some version of JNI and JNA. I spent weeks trying to get the tutorials to compile and didn't make any progress. On the other hand, I thought of this approach yesterday and can now communicate with my device through Java. The Python COM server provided a simple, straightforward way to interface Java with native applications. No UnsatisfiedLinkErrors, no Can't find librarys, no Classpath and JAVA_HOME issues. I didn't need to learn C or C++ and all the Python tutorials worked as described with no necessary modification.
To summarize, if you are having trouble reading native data types into Java, just set up a Python COM server and let Python's dynamic typing do the work for you.