6

Lets say I have test.proto file:

syntax = "proto3";

option java_package = "testing";
option java_outer_classname = "Test_v1";

import "google/protobuf/wrappers.proto";

message TestMessage {
    .google.protobuf.Int32Value integerField = 1;
}

If I compile (using protoc v3.5.0) it to c# code I will get nullable type properties:

public int? IntegerField {
   get { return integerField_; }
   set { integerField_ = value; }
 }

But if I compile it to Java code, fields will be of well-known type:

public Builder setIntegerField(com.google.protobuf.Int32Value value) {
  if (integerFieldBuilder_ == null) {
    if (value == null) {
      throw new NullPointerException();
    }
    integerField_ = value;
    onChanged();
  } else {
    integerFieldBuilder_.setMessage(value);
 }

I am moving project from proto2 to proto3 so I would like to avoid using well-known types, because it will require a lot of work to change related code. With c# projects I will not require to modify anything but in Java I will need to do as in the following example:

TestMessage.Builder builder = TestMessage.newBuilder();
builder.setIntegerField(5); //<-- instead of this with proto2
builder.setIntegerField(Int32Value.newBuilder().setValue(5)); //<-- I will need to do something like this with proto3

Is there a way to compile proto file to Java so setters would accept primitive classes/wrappers (String, Integer, etc.) as parameters?

Renatas M.
  • 11,694
  • 1
  • 43
  • 62

1 Answers1

4

The issue here is what to do when the value is missing. This isn't an issue with int32 (in the .proto), as (in proto3, at least) an int32 will always be there (defaulting to 0). However, an .google.protobuf.Int32Value is a message, and as such it can be missing, or represent a value (which might be 0). In C# this concept can be neatly represented via int? (which can be null), but Java has no concept similar to Nullable<T>. The Int32Value encapsulates this, allowing a null reference.

So short version: no, and (^^^) that's why.

I assume you're actually replacing something that used to be:

message TestMessage {
    optional int32 integerField = 1;
}

???

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 1
    Yes, you are correct. I am replacing optional (in proto 2) to well-known type(in proto3). I am not very strong in Java, but as I understand in Java land int is primitive and Integer is wrapper that can be null. So what we have in [c# Nullable might be the same as Integer in Java](https://stackoverflow.com/questions/14321175/how-to-write-nullable-int-in-java). That's why I was expecting to see `Integer` instead of `Int32Value`. I can get expected result if I change field in `.proto` file to be `oneof`, but using `oneofs` is not an option. – Renatas M. Jan 04 '18 at 13:54
  • 1
    @Reniuz yeah, that's a valid point - I can see how `Integer` would be fine there. I guess whoever implemented it just didn't want to do that, presumably to make it easier to provide expected `message` features rather than having to special-case `Integer`. – Marc Gravell Jan 04 '18 at 14:03
  • 1
    I posted question to [protobuf group](https://groups.google.com/forum/#!topic/protobuf/8q27h5uCUtk) and got an answer. [Functionality was already requested](https://github.com/google/protobuf/issues/2055) and the issue is still open. Thank you for your answer. I will accept it because the short version of an answer is correct :) – Renatas M. Jan 05 '18 at 08:39