Extensions in proto3 - protocol-buffers

Given the following proto definitions:
syntax = "proto3";
import "google/protobuf/descriptor.proto";
option java_package = "com.example.dto";
option java_multiple_files = true;
extend google.protobuf.FieldOptions {
Projector projector = 50002;
}
message Projector {
string name = 1;
string class = 2;
bool default = 3;
}
message SearchRequest {
string query = 1 [(projector) = {name: "queryProjector", class: "foobar"}];
int32 page_number = 2;
int32 result_per_page = 3;
}
How can I access the field extension?
As far as I understand extension still work in proto3, but are generally replaced by the Any type?
I came as this far:
final Descriptors.Descriptor descriptor = SearchRequest.getDescriptor();
final Descriptors.FieldDescriptor query = descriptor.findFieldByName("query");
Is this the right way? Whats the next step?

As stated here https://github.com/google/protobuf/issues/1460
Custom options are still supported. It's the only place where you can use extensions in proto3. It works the same way as in proto2. Languages that don't support proto2 may provide a special API to access custom options as they don't support extensions.
so custom options seem to be still supported and you should get them using
descriptor.findFieldByName("query").getOptions().getAllFields();
That would return you a map of your custom options (as fields)
final Map<Descriptors.FieldDescriptor, Object> allFields;
whereas the value would be the type of your option, Projector in your case.
The FileDescriptor for this custom option (projector) seems to be generated as a public static in a class named after your *.proto file using its camelCase name.
If your proto file is called search_service_v1.proto you might find the custom option directly as follows:
final DescriptorProtos.FieldOptions options descriptor.findFieldByName("query").getOptions();
final Object field = options.getField(SearchServiceV1.projector.getDescriptor());
And you'll get your extension by
final Projector projector = Projector.class.cast(field);

Related

In a proto3 message is there a way to mark a field as not required for requests and required for response?

I have the following proto3 message structure:
message BaseBuildContent {
string locale = 1;
string buildVersion = 2;
string buildLabel = 3;
google.protobuf.Timestamp createTime = 4;
}
I am using the "same" structure for some requests and responses on my app. What I want to achieve is to mark somehow (if possible) the createTime field as not required, in case we are talking about a request object, and required in case we are taking about a response object.
Is it possible to do this without creating a separate message ?
Thanks
To my knowledge, it's not possible and I'd discourage pursuing solutions other than defining distinct message types: one which includes the optional field and one which does not.
One way to solve this is to define a message that includes the mandatory fields and another than extends it:
message BaseBuildContent {
string locale = 1;
string buildVersion = 2;
string buildLabel = 3;
}
message SomeRequest {
BaseBuildContent content = 1;
}
message SomeResponse {
BaseBuildContent content = 1;
google.protobuf.Timestamp createTime = 2;
}
NOTE Protobuf style guide recommends message names be PascalCased and field names be snake_cased.

Castle Core Invocation create a cache key from intercepted method

I'm using a interface interceptor to cache all methods that starts with "Get" but i can't figure out how to generate a unique cache key for every unknown parameter it can be anything and using GetHashCode is not an option as i can't be 100% sure that they have overridden the GetHashCode.
some thoughts was someting in the line of How can I create a unique hashcode for a JObject?
where JSON is used for a JObject i was thinking on JSON serialize every parameter then get the hash code like explained in the link above:
var obj = JToken.Parse(jsonString);
var comparer = new JTokenEqualityComparer();
var hashCode = comparer.GetHashCode(obj);
However i think this will be a performence hit so how can this be solved ?
The code i have so far is this but it wont handle the complex type situation where .ToString won't generate the raw value type like int, string etc.
private string CreateCacheKey(IInvocation invocation)
{
string className = invocation.TargetType.FullName;
string methodName = invocation.Method.Name;
var builder = new StringBuilder(100);
builder.Append(className);
builder.Append(".");
builder.Append(methodName);
for (int i = 0; i < invocation.Arguments.Length; i++)
{
var argument = invocation.Arguments[i];
var argumentValue = invocation.GetArgumentValue(i);
builder.Append("_");
builder.Append(argument);
if (argument != argumentValue)
{
builder.Append(argumentValue);
}
}
return string.Format("{0}-{1}", this.provider.CacheKey, builder);
}
I ended up using GetHashCode as it is the only viable solution if thay dont override the method it will not cache.

Incorrect naming convention for fields in .proto files generated by protobuf-net?

I'm just getting started with Google Protocol Buffers and Marc Gravell's awesome protobuf-net program, and one thing I don't understand is the naming convention for the field declarations in a generated .proto file.
Here's what Google is recommending:
"Use underscore_separated_names for field names – for example, song_name."
https://developers.google.com/protocol-buffers/docs/style
"Note that method names always use camel-case naming, even if the field name in the .proto file uses lower-case with underscores (as it should)."
https://developers.google.com/protocol-buffers/docs/reference/java-generated
"Notice how these accessor methods use camel-case naming, even though the .proto file uses lowercase-with-underscores."
https://developers.google.com/protocol-buffers/docs/javatutorial
But when I use the Serializer.GetProto() method in protobuf-net on this:
[ProtoContract]
public partial class AuthEntry
{
private string _windowsAccount = "";
private string _machineNames = "*";
[ProtoMember(1)]
public string WindowsAccount
{
get { return _windowsAccount; }
set { _windowsAccount = value; }
}
[ProtoMember(2)]
public string MachineNames
{
get { return _machineNames; }
set { _machineNames = value; }
}
}
I get this:
message AuthEntry {
optional string WindowsAccount = 1;
optional string MachineNames = 2;
}
Instead of this, as I'd expected:
message AuthEntry {
optional string windows_account = 1;
optional string machine_names = 2;
}
I'm guessing it's no big deal, but just in case ...
The proto generation doesn't attempt to apply those conventions, because then it gets into the arms race of disambiguation, collisions, etc - no to mention the fun of finding word breaks in arbitrary names like CustomerIDReference (ok, that's an unlikely example, but you get the point). If you want to control that yourself - specify the Name property on either ProtoContractAttribute or ProtoMemberAttribute.

Protobuf C# Message Translation to JAVA

I am trying to translate a message generated using C# to JAVA. As a first step, i generated proto file and this is what i got
package Om.Business.Scanner;
message ScannerActivityDetail {
optional string ActivityId = 1;
optional string ContextId = 2;
optional int32 ActivityStart = 3;
optional bcl.DateTime ActivityEnd = 4;
}
How do i interpret bcl.DateTime in java world?
I am using protobuf-net and trying to de-serialize message generated by C# app.
Thanks in advance for your help.
Looking at bcl.proto, it should be pretty straightforward. Create a Map<DateTime.TimeSpanScale, TimeUnit> in the obvious way, then:
public static Date toDate(bcl.DateTime proto) {
TimeUnit unit = SCALE_TO_UNIT_MAP.get(proto.getScale());
if (unit == null) {
throw new IllegalArgumentException("Invalid scale: " + proto.getScale());
}
long millis = unit.toMillis(proto.getValue());
return new Date(millis);
}
You could use Joda Time's DateTime type in exactly the same way, as it has a constructor accepting a long too. (You might want to think about which time zone to specify though...)

Convert String into Class for TitleWindow

I don't know if this is possible, I am pulling the names for TitleWindows from my database as strings.
Then from my main application I have to launch the TitleWindow. So in my function I need to convert the name of the TitleWindow which is a String to a Class, because the PopUpManager accepts a Class. Below is my code.
When launching my application and trying to launch the TitleWindow I am getting the error:
Implicit coercion of a value of type String to an unrelated type Class.
I don't want to hard code the name of my popUp in the PopUpManager, that is why I am doing it like this. Any way to work around this?
public function getScreen(screenName:String):void
{
var screen_Name:Class = new Class();
screen_Name = screenName;
var popUpWindow:TitleWindow = PopUpManager.createPopUp(this, screen_Name, false) as TitleWindow;
PopUpManager.centerPopUp(popUpWindow);
}
I have had to do something very similar recently. Here is the function I wrote to do it:
//You have to provice the package signature
private var viewPackage:String = "org.bishop";
//In my case, event.type is the name of a class
var className: String = viewPackage + "." + event.type;
try{
var classRef:Class = getDefinitionByName(className) as Class;
viewNavigator.pushView(classRef);
}
catch(e:ViewError){
trace(e.message);
logger.debug(e.message);
}
Note: for the class to be created correctly, you will need to include both an import statement:
import org.bishop.Login;
and also declare a variable of the class in the code as follows:
Login;
otherwise the classes will not be available to be created.

Resources