how use protocol buffers? - java

I watched a lot of tutorials, but I can not understand how to use protocol buffers
Why "message User "? why not "class User "? and how Eclipse has created such a message?
and why name = 2 ? not name = "Max"
ption java_outer_classname="ProtoUser";
message User {
required int32 id = 1; // DB record ID
required string name = 2;
required string firstname = 3;
required string lastname = 4;
required string ssn= 5;
// Embedded Address message spec
message Address {
required int32 id = 1;
required string country = 2 [default = "US"];;
optional string state = 3;
optional string city = 4;
optional string street = 5;
optional string zip = 6;
enum Type {
HOME = 0;
WORK = 1;
}
optional Type addrType = 7 [default = HOME];
}
repeated Address addr = 16;
}

Why "message User "? why not "class User "?
Google Protocol Buffers (GPB) does not have class in its syntax, it has message instead.
https://developers.google.com/protocol-buffers/docs/style
This file is just text file, it should have .proto extension. After all you will run a utility on it which would generate real Java classes which you can import and easily use in your project.
https://developers.google.com/protocol-buffers/docs/javatutorial
Compiling Your Protocol Buffers
protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/addressbook.proto
required string lastname = 4;
4 stands for the field id, not a value, it is going to be used to generate a bit stream.

Protobuffer use message(keyword) instead of class
Inside the class you define the structure of. schema.
For example
message Person{
string name = 1;
repeated string id = 2;
Type phoneType = 3;
}
enum Type{
CellPhone = 0;
HomePhone = 1;
}
In the above example, we are defining the structure of the Person Message.
It has name which datatype is a string, id which is an array of the string and type(when you expect only certain values then use an enum. In this case, we assume that phoneNumber can be either CellPhone or HomePhone. If someone is sending any other value then IT will through UNKNOWN proto value exception)
required: means parameter is required
To use proto first create proto classes using mvn clean install
Then create protobuilder
Protobuilder to set for above proto
Person person = Person.newBuilder().setName("testName")
.setPhoneType(Type.CellPhone)
.addAllId(listIds)
.build;
Once you set the value you can not change it. If you want to change the value then you need to create another proto.
Pesron person1 = Person.newBuilder(person).setName("ChangeName").build;
person1 will have the name ChangeName, phoneType CellPhone, and ids arrays of strings.
More information: https://developers.google.com/protocol-buffers

Related

Proto Message - Get Field by String (name)

I want to get a specific Field from a proto Message with a String, i will try my best to explain what i need to know:
For example we have this .proto File:
message Employee {
string id = 1;
PersonData person_data = 2;
...
}
message PersonData {
string first_name = 1;
string surname = 2;
...
}
Now iam getting a String with a field name like "person_data.first_name".
For example if you want to get the id you must just write:
FieldDescriptor fieldDescriptor = message.getDescriptorForType().findFieldByName("id");
But i need the field "first_name". How can i manage this?
I tried a lot of methods but nothing worked.
Anyone any ideas?

RavenDB query returns null

I'm on RavenDB 3.5.35183. I have a type:
import com.mysema.query.annotations.QueryEntity;
#QueryEntity
public class CountryLayerCount
{
public String countryName;
public int layerCount;
}
and the following query:
private int getCountryLayerCount(String countryName, IDocumentSession currentSession)
{
QCountryLayerCount countryLayerCountSurrogate = QCountryLayerCount.countryLayerCount;
IRavenQueryable<CountryLayerCount> levelDepthQuery = currentSession.query(CountryLayerCount.class, "CountryLayerCount/ByName").where(countryLayerCountSurrogate.countryName.eq(countryName));
CountryLayerCount countryLayerCount = new CountryLayerCount();
try (CloseableIterator<StreamResult<CountryLayerCount>> results = currentSession.advanced().stream(levelDepthQuery))
{
while(results.hasNext())
{
StreamResult<CountryLayerCount> srclc = results.next();
System.out.println(srclc.getKey());
CountryLayerCount clc = srclc.getDocument();
countryLayerCount = clc;
break;
}
}
catch(Exception e)
{
}
return countryLayerCount.layerCount;
}
The query executes successfully, and shows the correct ID for the document I'm retrieving (e.g. "CountryLayerCount/123"), but its data members are both null. The where clause also works fine, the country name is used to retrieve individual countries. This is so simple, but I can't see where I've gone wrong. The StreamResult contains the correct key, but getDocument() doesn't work - or, rather, it doesn't contain an object. The collection has string IDs.
In the db logger, I can see the request coming in:
Receive Request # 29: GET - geodata - http://localhost:8888/databases/geodata/streams/query/CountryLayerCount/ByName?&query=CountryName:Germany
Request # 29: GET - 22 ms - geodata - 200 - http://localhost:8888/databases/geodata/streams/query/CountryLayerCount/ByName?&query=CountryName:Germany
which, when plugged into the browser, correctly gives me:
{"Results":[{"countryName":"Germany","layerCount":5,"#metadata":{"Raven-Entity-Name":"CountryLayerCounts","Raven-Clr-Type":"DbUtilityFunctions.CountryLayerCount, DbUtilityFunctions","#id":"CountryLayerCounts/212","Temp-Index-Score":0.0,"Last-Modified":"2018-02-03T09:41:36.3165473Z","Raven-Last-Modified":"2018-02-03T09:41:36.3165473","#etag":"01000000-0000-008B-0000-0000000000D7","SerializedSizeOnDisk":164}}
]}
The index definition:
from country in docs.CountryLayerCounts
select new {
CountryName = country.countryName
}
AFAIK, one doesn't have to index all the fields of the object to retrieve it in its entirety, right ? In other words, I just need to index the field(s) to find the object, not all the fields I want to retrieve; at least that was my understanding...
Thanks !
The problem is related to incorrect casing.
For example:
try (IDocumentSession sesion = store.openSession()) {
CountryLayerCount c1 = new CountryLayerCount();
c1.layerCount = 5;
c1.countryName = "Germany";
sesion.store(c1);
sesion.saveChanges();
}
Is saved as:
{
"LayerCount": 5,
"CountryName": "Germany"
}
Please notice we use upper case letters in json for property names (this only applies to 3.X versions).
So in order to make it work, please update json properties names + edit your index:
from country in docs.CountryLayerCounts
select new {
CountryName = country.CountryName
}
Btw. If you have per country aggregation, then you can simply query using:
QCountryLayerCount countryLayerCountSurrogate =
QCountryLayerCount.countryLayerCount;
CountryLayerCount levelDepthQuery = currentSession
.query(CountryLayerCount.class, "CountryLayerCount/ByName")
.where(countryLayerCountSurrogate.countryName.eq(countryName))
.single();

Use csv data as string java

This maybe simple but java isn’t really my thing but I'm working with a java API.
I need to parse a csv file and use the values as strings.
CSV file:
Mac,device,level ,key number,key function ,name,number,prim
01:1A:E8:84:9D:27,0,0,1,31,line,441865945218,TRUE
01:1A:E8:84:9D:27,0,0,2,51,dss,441865985452,FALSE
each row need to be read seprately so something like.
Read first row of csv
Assign values to strings (e.g. mac = 01:1A:E8:84:9D:27 device = 0 and so on)
Run "code" using these strings
Read second row of csv
So on till end of csv.
Thanks
I have tried csvreader but I'm not able to use the strings outside of the while function and it does not read line by line.
CsvReader phones = new CsvReader("dls.csv");
phones.readHeaders();
while (phones.readRecord()){
String deviceID = phones.get("Mac");
String device = phones.get("device");
String level = phones.get("level");
String keynumber = phones.get("key number");
String keyfunction = phones.get("key Function");
String label = phones.get("name");
String e164 = phones.get("number");
String prim = phones.get("prim");
}
As you are new to Java, whatever you are doing, looks like it reads the file line by line. But as you are defining the Strings in while loop, you won't be able to access it outside.
If you want to read all lines and store in Strings, you should probably take array for all of them and define them outside the while loop, add values in the loop and then you'll be able to use it.
Or just create a Phone class:
public class Phone{
String deviceId;
String device;
......etc...
//setters and getters
}
And take an array of it outside while. Something like this:
CsvReader phones = new CsvReader("dls.csv");
phones.readHeaders();
List<Phone> phonesArr=new ArrayList<Phone>();
while (phones.readRecord())
{
Phone phone=new Phone();
phone.setDeviceId(phones.get("Mac"));
phone.setDevice(phones.get("device"));
.....
phones.add(phone);
}
// array phones will be accessible here
Hope that helps!
You have to declare the Strings outside of the loop. Otherwise the String variables would be loop scoped.
CsvReader phones = new CsvReader("dls.csv");
phones.readHeaders();
String deviceID;
String device;
String level;
String keynumber;
String keyfunction;
String label;
String e164;
String prim;
while (phones.readRecord()){
deviceID = phones.get("Mac");
device = phones.get("device");
level = phones.get("level");
keynumber = phones.get("key number");
keyfunction = phones.get("key Function");
label = phones.get("name");
e164 = phones.get("number");
prim = phones.get("prim");
}
See:
Scopes tutorial
Javadoc: Variables
In the end I just called the funtion from the while loop.
while (phones.readRecord()) {
deviceID = phones.get("Mac");
Device = phones.get("device");
Level = phones.get("level");
Keynumber = phones.get("key number");
Keyfunction = phones.get("key function");
Label = phones.get("name");
E164 = phones.get("number");
Prim = phones.get("prim");
tools connect = new tools();
connect.connect();
connect.setkeys(deviceID,Device,Level,Label,Keynumber,Keyfunction,E164,Prim);
//System.out.println(Prim);
}
phones.close();

"Generic" Parameters on model (Java)

In C # I could use (on data-annotations) this code below without problems:
[RegularExpression(#"^myRegex$", ErrorMessage = "The field {0} is not in the correct format.")]
public string Name { get; set; }
But in Java it doesn't work, I tried it:
#Pattern(regexp = "^myRegex$", message = "The field {0} is not in the correct format.")
private String name;
The {0} just return {0}, not the "name" field.
So, could someone help me with some example in Java to make it work?

toByeArray doesn't exist in my java protobuffer

I am using protoc version 2.5 and the protobuf-java-2.5.0.jar file to compile the following protobuff
// This is the type for a publisher looking to sell digital real-estate
message Publisher {
required string name = 1;
required int32 id = 2; // Unique ID number for this person.
required double ask_price = 3;
optional string email = 4;
enum MediaType {
WEB = 0;
NEWSPAPER = 1;
MAGAZINE = 2;
}
optional MediaType media = 5;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 6;
}
I then have the following line in my java code that generates a random Publisher Object by setting the data members on a Publisher.Builder and then calling .build() and returning the result.
Publisher pub = genPubProtoBuf();
However, pub DOES NOT HAVE the method "toByteArray()". pub is clearly a Publisher which extends Generated Message which extends AbstractMessageLite where toByteArray() is a public method, so Publisher should have it as well. Am I missing something obvious and not correctly building my Publisher Object?
Even stranger, when I look at the .java file that holds the generated code for Publisher, I can't find any mention of toByteArray(), there is only the parseFrom(byte[]) method.
EDIT: The code where I'm calling pub.toByteArray is given below:
while (true) {
Publisher pub = genPubProtoBuf();
String key = pub.getName() + pub.getEmail() + pub.getMedia().toString() + pub.getPhone(0);
byte[] byteArr = pub.toByteArray();
KeyedMessage<String, byte[]> data = new KeyedMessage<String, byte[]>("simple-topic", key, byteArr);
producer.send(data);
try {
Thread.sleep(dataProductionInterval);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}

Categories

Resources