4

My Enum original java code is:

public enum CarModel {
    NOMODEL("NOMODEL");
    X("X"),
    XS("XS"),
    XSI("XS-I"); //NOTE the special - character. Can't be declared XS-I
    XSI2("XS-I.2"); //NOTE the special . character. Can't be declared XS-I.2
    private final String carModel;
    CarModel(String carModel) { 
        this.carModel = carModel;
    }

    public String getCarModel() { return carModel; }

    public static CarModel fromString(String text) {
        if (text != null) {
            for (CarModel c : CarModel.values()) {
                if (text.equals(c.carModel)) {
                    return c;
                }
            }
        }
        return NOMODEL; //default
    }
}

Now if I use protobuf I get in the .proto file:

enum CarModel {
    NOMODEL = 0;
    X = 1;
    XS = 2;
    XSI = 3;
    XSI2 = 4;
}

from my earlier question I know I can call the enum generated by protoc and remove my own class (and thus avoid the duplicate value definitions) but I still need to define somewhere (In a wrapper class? wrapper enum class?) the alternate fromString() method that will return the right string per the enum. How do I do that?

EDIT: How do I implement the following:

String carModel = CarModel.XSI.toString(); This will return "XS-I"

and:

CarModel carModel = CarModel.fromString("XS-I.2");
Community
  • 1
  • 1
Dror Cohen
  • 6,731
  • 5
  • 29
  • 32

2 Answers2

9

You can accomplish this using Protobuf's "custom options".

import "google/protobuf/descriptor.proto";

option java_outer_classname = "MyProto";
// By default, the "outer classname" is based on the proto file name.
// I'm declaring it explicitly here because I use it in the example
// code below.  Note that even if you use the java_multiple_files
// option, you will need to use the outer classname in order to
// reference the extension since it is not declared in a class.

extend google.protobuf.EnumValueOptions {
  optional string car_name = 50000;
  // Be sure to read the docs about choosing the number here.
}

enum CarModel {
  NOMODEL = 0 [(car_name) = "NOMODEL"];
  X = 1 [(car_name) = "X"];
  XS = 2 [(car_name) = "XS"];
  XSI = 3 [(car_name) = "XS-I"];
  XSI2 = 4 [(car_name) = "XS-I.2"];
}

Now in Java you can do:

String name =
    CarModel.XSI.getValueDescriptor()
    .getOptions().getExtension(MyProto.carName);
assert name.equals("XS-I");

https://developers.google.com/protocol-buffers/docs/proto#options (Scroll down slightly to the section on custom options.)

Kenton Varda
  • 41,353
  • 8
  • 121
  • 105
  • I've tried your code and it seems the protoc doesn't create the getProto() method I need to call in order to translate the ValueDescriptor to Extension. Any Ideas ? – Dror Cohen Oct 10 '13 at 07:16
  • one more thing - when looking in the generated java code the only place where the "XS-I" and "XS-I.2" strings appear are in the last field that is defined as: "static {java.lang.String[] descriptorData = {" and basically holds my .proto source – Dror Cohen Oct 10 '13 at 07:34
  • Oops, sorry, the method is called `toProto`, not `getProto`. I'll edit my answer. Yes, the annotations all go into descriptorData. The code I gave actually fetches them out of there. – Kenton Varda Oct 10 '13 at 20:34
  • toProto indeed exists but still no getExtension... Any ideas? – Dror Cohen Oct 14 '13 at 18:58
  • Sorry, I forgot that extensions hang off the options proto, not the descriptor proto. So I guess you need `getOptions()` rather than `toProto()`. Updated example again. – Kenton Varda Oct 14 '13 at 21:30
-1
CarModel carmodel =  Enum.valueOf(CarModel.class, "XS")

or

CarModel carmodel =  CarModel.valueOf("XS");
Prabhakaran Ramaswamy
  • 25,706
  • 10
  • 57
  • 64
  • I need the other direction: String model = CarModel.XSI.toString(); but to be able to tell it that XSI translates to "XS-I". And also the following CarModel carModel = CarModel.fromString("XS-I"); – Dror Cohen Oct 08 '13 at 07:33