-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
1d35a65b.60a9b776.js
1 lines (1 loc) · 48.7 KB
/
1d35a65b.60a9b776.js
1
(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{119:function(e,t,a){"use strict";a.d(t,"a",(function(){return b})),a.d(t,"b",(function(){return d}));var n=a(0),o=a.n(n);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function s(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function l(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?s(Object(a),!0).forEach((function(t){i(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):s(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function p(e,t){if(null==e)return{};var a,n,o=function(e,t){if(null==e)return{};var a,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||(o[a]=e[a]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(o[a]=e[a])}return o}var r=o.a.createContext({}),c=function(e){var t=o.a.useContext(r),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},b=function(e){var t=c(e.components);return o.a.createElement(r.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.a.createElement(o.a.Fragment,{},t)}},u=o.a.forwardRef((function(e,t){var a=e.components,n=e.mdxType,i=e.originalType,s=e.parentName,r=p(e,["components","mdxType","originalType","parentName"]),b=c(a),u=n,d=b["".concat(s,".").concat(u)]||b[u]||m[u]||i;return a?o.a.createElement(d,l(l({ref:t},r),{},{components:a})):o.a.createElement(d,l({ref:t},r))}));function d(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=a.length,s=new Array(i);s[0]=u;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l.mdxType="string"==typeof e?e:n,s[1]=l;for(var r=2;r<i;r++)s[r]=a[r];return o.a.createElement.apply(null,s)}return o.a.createElement.apply(null,a)}u.displayName="MDXCreateElement"},79:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return l})),a.d(t,"metadata",(function(){return p})),a.d(t,"toc",(function(){return r})),a.d(t,"default",(function(){return b}));var n=a(3),o=a(7),i=(a(0),a(119)),s=["components"],l={title:"Customizations",layout:"docs"},p={unversionedId:"customizations",id:"customizations",isDocsHomePage:!1,title:"Customizations",description:"Getting started with scalapb.proto",source:"@site/../docs/target/mdoc/customizations.md",slug:"/customizations",permalink:"/docs/customizations",version:"current",sidebar:"someSidebar",previous:{title:"Protocol Buffer Tutorial: Scala",permalink:"/docs/getting-started"},next:{title:"SBT Settings",permalink:"/docs/sbt-settings"}},r=[{value:"Getting started with scalapb.proto",id:"getting-started-with-scalapbproto",children:[]},{value:"ScalaPB File-level Options",id:"scalapb-file-level-options",children:[]},{value:"File-level options",id:"file-level-options",children:[]},{value:"Package-scoped options",id:"package-scoped-options",children:[{value:"Publishing package-scoped options",id:"publishing-package-scoped-options",children:[]},{value:"Disabling package-scoped options processing",id:"disabling-package-scoped-options-processing",children:[]}]},{value:"Auxiliary options",id:"auxiliary-options",children:[]},{value:"Primitive wrappers",id:"primitive-wrappers",children:[]},{value:"Custom base traits for messages",id:"custom-base-traits-for-messages",children:[]},{value:"Custom base traits for sealed oneofs",id:"custom-base-traits-for-sealed-oneofs",children:[]},{value:"Custom base traits for sealed oneofs companion objects",id:"custom-base-traits-for-sealed-oneofs-companion-objects",children:[]},{value:"Custom base traits for enums",id:"custom-base-traits-for-enums",children:[]},{value:"Custom types",id:"custom-types",children:[]},{value:"Message-level custom type and boxing",id:"message-level-custom-type-and-boxing",children:[]},{value:"Custom types on maps",id:"custom-types-on-maps",children:[]},{value:"Custom collection types",id:"custom-collection-types",children:[]},{value:"Custom names",id:"custom-names",children:[]},{value:"Adding annotations",id:"adding-annotations",children:[]},{value:"Adding derives clause",id:"adding-derives-clause",children:[]}],c={toc:r};function b(e){var t=e.components,a=Object(o.a)(e,s);return Object(i.b)("wrapper",Object(n.a)({},c,a,{components:t,mdxType:"MDXLayout"}),Object(i.b)("h2",{id:"getting-started-with-scalapbproto"},"Getting started with scalapb.proto"),Object(i.b)("p",null,"ScalaPB's code generator provides supports many different customizations. To\nget access to these customizations, you need to import ",Object(i.b)("inlineCode",{parentName:"p"},"scalapb/scala.proto"),"\nin the proto files you want to customize. You can also have the options apply\nto an entire proto3 package by using package-scoped options (see below)."),Object(i.b)("p",null,"To have ",Object(i.b)("inlineCode",{parentName:"p"},"scalapb/scalapb.proto")," available to be imported in your project, add\nthe following SBT setting in your ",Object(i.b)("inlineCode",{parentName:"p"},"build.sbt"),":"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre"},'libraryDependencies += "com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf"\n')),Object(i.b)("p",null,"If you are invoking ",Object(i.b)("inlineCode",{parentName:"p"},"protoc")," manually, you will need to ensure that the files in\n",Object(i.b)("a",{parentName:"p",href:"https://github.com/scalapb/ScalaPB/tree/master/protobuf"},Object(i.b)("inlineCode",{parentName:"a"},"protobuf")),"\ndirectory are available to your project."),Object(i.b)("h2",{id:"scalapb-file-level-options"},"ScalaPB File-level Options"),Object(i.b)("p",null,"ScalaPB file-level options lets you"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"specify the name of the Scala package to use (the default is using the java package name)."),Object(i.b)("li",{parentName:"ul"},"request that ScalaPB will not append the protofile name to the package name."),Object(i.b)("li",{parentName:"ul"},"specify Scala imports so custom base traits and custom types (see below) do\nnot require the full class name.")),Object(i.b)("p",null,"The file-level options are not required, unless you are interested in those\ncustomizations. If you do not want to customize the defaults, you can safely\nskip this section."),Object(i.b)("h2",{id:"file-level-options"},"File-level options"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'import "scalapb/scalapb.proto";\n\noption (scalapb.options) = {\n scope: FILE\n package_name: "com.example.myprotos"\n flat_package: true\n single_file: true\n java_conversions: false\n import: "com.thesamet.pb.MyType"\n import: "com.thesamet.other._"\n preamble: "sealed trait BaseMessage"\n preamble: "sealed trait CommonMessage"\n lenses: true\n getters: true\n retain_source_code_info: false\n no_default_values_in_constructor: false\n preserve_unknown_fields: false\n enum_value_naming: CAMEL_CASE\n enum_strip_prefix: false\n bytes_type: "scodec.bits.ByteVector"\n scala3_sources: false\n public_constructor_parameters: false\n};\n')),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},Object(i.b)("inlineCode",{parentName:"p"},"scope")," controls whether the specified options apply only for this proto\nfiles or for the entire package. Default is ",Object(i.b)("inlineCode",{parentName:"p"},"FILE"),". See ",Object(i.b)("a",{parentName:"p",href:"#package-scoped-options"},"package-scoped options"),"\nfor more details.")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},Object(i.b)("inlineCode",{parentName:"p"},"package_name")," sets the Scala base package name, if this is not defined,\nthen it falls back to the ",Object(i.b)("inlineCode",{parentName:"p"},"java_package")," option. If the ",Object(i.b)("inlineCode",{parentName:"p"},"java_package")," option\nis also not the found, then the package name from file's ",Object(i.b)("inlineCode",{parentName:"p"},"package")," statement\nis used.")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Setting ",Object(i.b)("inlineCode",{parentName:"p"},"flat_package")," to true (default is ",Object(i.b)("inlineCode",{parentName:"p"},"false"),") makes ScalaPB not append\nthe protofile base name to the package name. You can also apply this option\nglobally to all files by adding it to your ",Object(i.b)("a",{parentName:"p",href:"/docs/sbt-settings"},"ScalaPB SBT Settings"),".")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"The ",Object(i.b)("inlineCode",{parentName:"p"},"single_file")," option makes the generator output all messages and\nenums to a single Scala file.")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"The ",Object(i.b)("inlineCode",{parentName:"p"},"java_conversions")," options tells ScalaPB to generate converters to the\ncorresponding Java messages in this file. It does not automatically trigger\nJava source code generation for the messages. If you need to generate source code\nin Java, include ",Object(i.b)("inlineCode",{parentName:"p"},"PB.gens.java")," in the list of targets in sbt-protoc.")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"The ",Object(i.b)("inlineCode",{parentName:"p"},"preamble")," is a list of strings that is output at the top of the\ngenerated Scala file. This option requires ",Object(i.b)("inlineCode",{parentName:"p"},"single_file")," to be set. It is\ncommonly used to define sealed traits that are extended using\n",Object(i.b)("inlineCode",{parentName:"p"},"(scalapb.message).extends")," - see custom base traits below and ",Object(i.b)("a",{parentName:"p",href:"https://github.com/scalapb/ScalaPB/blob/master/e2e/src/main/protobuf/nocode/sealed_trait.proto"},"this example"),".")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"The ",Object(i.b)("inlineCode",{parentName:"p"},"object_name")," option lets you customize the name of the generated class\nthat contains various file-level members such as descriptors and a list of\ncompanion objects for the generated messages and enums. This is useful in\ncase you are running into issues where the generated class name conflicts\nwith other things in your project.")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Setting ",Object(i.b)("inlineCode",{parentName:"p"},"lenses")," to ",Object(i.b)("inlineCode",{parentName:"p"},"false")," inhibits generation of lenses (default is ",Object(i.b)("inlineCode",{parentName:"p"},"true"),").")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Setting ",Object(i.b)("inlineCode",{parentName:"p"},"getters")," to ",Object(i.b)("inlineCode",{parentName:"p"},"false")," inhibits generation of getters (default is ",Object(i.b)("inlineCode",{parentName:"p"},"true"),").")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Setting ",Object(i.b)("inlineCode",{parentName:"p"},"retain_source_code_info")," to ",Object(i.b)("inlineCode",{parentName:"p"},"true")," retains information in the descriptor that\ncan be used to retrieve source code information from the descriptor at\nruntime (such as comments and source code locations). This option is turned\noff by default to conserve source size and memory at runtime. When this\noption is enabled, use the ",Object(i.b)("inlineCode",{parentName:"p"},"location")," method on various descriptors to\naccess source code information.")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"By default, all non-required fields have default values in the constructor of the generated\ncase classes. When setting ",Object(i.b)("inlineCode",{parentName:"p"},"no_default_values_in_constructor")," to ",Object(i.b)("inlineCode",{parentName:"p"},"true")," no\ndefault values will be generated for all fields. There is also a\nmessage-level ",Object(i.b)("inlineCode",{parentName:"p"},"no_default_values_in_constructor")," and field-level\n",Object(i.b)("inlineCode",{parentName:"p"},"no_default_value_in_constructor"),". If the field-level setting is set, it\noverrides the message-level. If the message-level setting is set, it overrides\nthe file-level setting.")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Typically, enum values appear in UPPER_CASE in proto files, and ScalaPB generates case objects\nwith exactly the same name in Scala. If you would like ScalaPB to transform the names into CamelCase, set ",Object(i.b)("inlineCode",{parentName:"p"},"enum_value_naming")," to ",Object(i.b)("inlineCode",{parentName:"p"},"CAMEL_CASE"),".")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"It is a common practice in protobufs to prefix each enum value name with the name of the enum.\nFor example, an enum name ",Object(i.b)("inlineCode",{parentName:"p"},"Size")," may have values named ",Object(i.b)("inlineCode",{parentName:"p"},"SIZE_SMALL")," and ",Object(i.b)("inlineCode",{parentName:"p"},"SIZE_LARGE"),". When you set ",Object(i.b)("inlineCode",{parentName:"p"},"enum_strip_prefix"),"\nto ",Object(i.b)("inlineCode",{parentName:"p"},"true"),", ScalaPB will strip the enum's name from each value name, and they would become ",Object(i.b)("inlineCode",{parentName:"p"},"SMALL")," and ",Object(i.b)("inlineCode",{parentName:"p"},"LARGE"),".\nThen the name can be transformed to camel-case according to ",Object(i.b)("inlineCode",{parentName:"p"},"enum_value_naming"),". Note that the prefix that is removed\nis the all-caps version of the enum name followed by an underscore.")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"By default, during deserialization only known fields are retained.\nWhen setting ",Object(i.b)("inlineCode",{parentName:"p"},"preserve_unknown_fields")," to ",Object(i.b)("inlineCode",{parentName:"p"},"true"),", all generated messages in this file will preserve unknown fields.\nThis is default behaviour in java for Proto3 messages since 3.5.0.\nIn ScalaPB 0.10.0: the default of this field became ",Object(i.b)("inlineCode",{parentName:"p"},"true")," for consistency\nwith Java.")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Use ",Object(i.b)("inlineCode",{parentName:"p"},"bytes_type")," to customize the Scala type used for the ",Object(i.b)("inlineCode",{parentName:"p"},"bytes")," field\ntype. You will need to have an implicit\n",Object(i.b)("inlineCode",{parentName:"p"},"TypeMapper[com.google.protobuf.ByteString, YourType]")," instance so ScalaPb\ncan convert back and forth to the type of your choice. That implicit will be\nfound if it is defined under ",Object(i.b)("inlineCode",{parentName:"p"},"YourType")," companion object, or on a package\nobject that matches the generated code (or any of its parent packages).")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"By default, ScalaPB generates Scala sources that are compatible with both Scala 2 and Scala 3. To generate sources that can be compiled error-free with ",Object(i.b)("inlineCode",{parentName:"p"},"-source feature")," on Scala 3 or with ",Object(i.b)("inlineCode",{parentName:"p"},"-Xsource:3")," on Scala 2.13, set ",Object(i.b)("inlineCode",{parentName:"p"},"scala3_sources")," to ",Object(i.b)("inlineCode",{parentName:"p"},"true")," or pass the ",Object(i.b)("inlineCode",{parentName:"p"},"scala3_sources")," generator parameter.")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("p",{parentName:"li"},"Use ",Object(i.b)("inlineCode",{parentName:"p"},"public_constructor_parameters")," to make constructor parameters public, including defaults and TypeMappers.\nThis is helpful for automated schema derivation with e.g. ",Object(i.b)("inlineCode",{parentName:"p"},"magnolia")," when trying to also derive default fields by\nusing the compiler flag ",Object(i.b)("inlineCode",{parentName:"p"},"-Yretain-trees"),". Without this flag, the companion object's ",Object(i.b)("inlineCode",{parentName:"p"},"_typemapper_*")," fields are private."))),Object(i.b)("h2",{id:"package-scoped-options"},"Package-scoped options"),Object(i.b)("p",null,"Note: this option is available in ScalaPB 0.8.2 and later."),Object(i.b)("p",null,"Sometimes you want to have the same file-level options applied to all\nthe proto files in your project. To accomplish that, add a ",Object(i.b)("inlineCode",{parentName:"p"},"package.proto"),"\nfile (the name does not matter) next to your proto files that looks like this:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre"},'import "scalapb/scalapb.proto";\n\npackage com.mypackage;\n\noption (scalapb.options) = {\n scope: PACKAGE\n flat_package: true\n};\n')),Object(i.b)("p",null,"All the options in this file will be applied to all proto files in the\npackage ",Object(i.b)("inlineCode",{parentName:"p"},"com.mypackage")," and its sub-packages."),Object(i.b)("p",null,"There is no need to explicitly import this file from other protos. If you are\nusing ",Object(i.b)("inlineCode",{parentName:"p"},"sbt-protoc")," and the file is in the proto source directory (default is\n",Object(i.b)("inlineCode",{parentName:"p"},"src/main/protobuf"),") then the file will be found and the options applied. If\nyou are invoking protoc in another way, you need to ensure that this\nfile is passed to protoc together with the rest of the files."),Object(i.b)("p",null,"If you are generating Scala code for proto files that you don't own, you can\nuse this feature to customize code generation by creating a ",Object(i.b)("inlineCode",{parentName:"p"},"package.proto"),"\nfile for that third-party package and include it within your proto source\ndirectory."),Object(i.b)("p",null,"The following rules are applied when validating package-scoped options:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"At most one file in each package may provide package-scoped options."),Object(i.b)("li",{parentName:"ul"},"Sub-packages may override package-scoped options provided by their parent\npackages. The options are merged using the Protocol Buffers ",Object(i.b)("inlineCode",{parentName:"li"},"mergeFrom"),"\nsemantics. Specifically, this implies that repeated fields such as ",Object(i.b)("inlineCode",{parentName:"li"},"import"),"\nand ",Object(i.b)("inlineCode",{parentName:"li"},"preamble")," are concatenated."),Object(i.b)("li",{parentName:"ul"},"Proto files get the most specific package-scoped options for the package\nthey are in. File-level options defined in a proto file get merged with the\npackage-level options using ",Object(i.b)("inlineCode",{parentName:"li"},"mergeFrom"),"."),Object(i.b)("li",{parentName:"ul"},"Proto files with package-scoped options must have a ",Object(i.b)("inlineCode",{parentName:"li"},"package")," statement.\nThis is to prevent the possibility of options applied globally. Standard\nclasses that are shipped with ScalaPB already assume certain options, so\noverriding options globally may lead to compilation errors.")),Object(i.b)("h3",{id:"publishing-package-scoped-options"},"Publishing package-scoped options"),Object(i.b)("p",null,"If you are publishing a library that includes protos with package-scoped\noptions, you need to make sure your library users source the package-scoped\noption proto file so the customizations are applied when they generate code."),Object(i.b)("p",null,"Your users can simply import your package-scoped options from any proto file\nin their project to have the settings applied (a single import of\nthe package-scoped options file would apply it globally for the code generator).\nHowever, since ScalaPB 0.10.11 and sbt-protoc 1.0.1, sbt-protoc provides a way to automate this with no\nneed to manually import the package-scoped options file. This is accomplished\nby including a special attribute in the manifest of the library you publish. Add the following to\nyour library's settings:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-scala"},'Compile / packageBin / packageOptions += (\n Package.ManifestAttributes("ScalaPB-Options-Proto" -> "path/to/package.proto")\n)\n')),Object(i.b)("p",null,"The path above is relative to the root directory of the published JAR (so ",Object(i.b)("inlineCode",{parentName:"p"},"src/main/protobuf")," is not needed). Users add your library to their projects like this:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-scala"},'libraryDependencies ++= Seq(\n "com.example" %% "your-library" % "0.1.0",\n "com.example" %% "your-library" % "0.1.0" % "protobuf"\n)\n')),Object(i.b)("p",null,"The first dependency provides the precompiled class files. The second dependency makes it possible\nfor users to import the protos in the jar file. ",Object(i.b)("inlineCode",{parentName:"p"},"sbt-protoc")," will look for the\n",Object(i.b)("inlineCode",{parentName:"p"},"ScalaPB-Options-Proto")," attribute in the jar's manifest and automatically add the package scoped options file\nto the protoc command line."),Object(i.b)("div",{className:"admonition admonition-note alert alert--secondary"},Object(i.b)("div",{parentName:"div",className:"admonition-heading"},Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",{parentName:"h5",className:"admonition-icon"},Object(i.b)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},Object(i.b)("path",{parentName:"svg",fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))),"note")),Object(i.b)("div",{parentName:"div",className:"admonition-content"},Object(i.b)("p",{parentName:"div"},"Since the package-scoped options file is used as a source file in multiple\nprojects, it should not define any types (messages, enums, services).\nThis ensures that the package-scoped proto file does not generate any code on its own so we don't\nend up with duplicate class files."))),Object(i.b)("h3",{id:"disabling-package-scoped-options-processing"},"Disabling package-scoped options processing"),Object(i.b)("p",null,"As a consumer of third-party dependencies that come with options proto, you\ncan disable the behavior of automatically adding the options proto to protoc\nby setting"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-scala"},"Compile / PB.manifestProcessing := false\n")),Object(i.b)("p",null,"in sbt. In that case, it is your responsibility to either manually ",Object(i.b)("inlineCode",{parentName:"p"},"import")," the option protos in one\nof your own project source files so it gets applied, or ensure that the\ngenerator settigs used in your project are consistent with the ones used to\ngenerate the dependency. Differences in settings can lead to generated code\nthat does not compile."),Object(i.b)("h2",{id:"auxiliary-options"},"Auxiliary options"),Object(i.b)("p",null,"In some situations, you may want to set some options in a proto file, but without\nmodifying the original proto file or adding anything ScalaPB-specific to it. To accomplish\nthat, you can define auxiliary options under package-scoped options."),Object(i.b)("p",null,"For example, if you are given this proto file:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'syntax = "proto3";\npackage a.b.c;\nmessage Foo {\n string hello = 1;\n}\n')),Object(i.b)("p",null,"You can add a file ",Object(i.b)("inlineCode",{parentName:"p"},"package.proto")," with the following content:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'syntax = "proto3";\npackage a.b.c;\nimport "scalapb/scalapb.proto";\noption (scalapb.options) = {\n scope: PACKAGE\n aux_message_options: [\n {\n target: "a.b.c.Foo"\n options: {\n extends: "com.myexample.SomeTrait"\n }\n }\n ]\n aux_field_options: [\n {\n target: "a.b.c.Foo.hello"\n options: {\n scala_name: "goodbye"\n }\n }\n ]\n};\n')),Object(i.b)("p",null,"The list ",Object(i.b)("inlineCode",{parentName:"p"},"aux_message_options")," contains options targeted at different messages define under the same proto package of the package-scoped options. The ",Object(i.b)("inlineCode",{parentName:"p"},"target")," name needs to be fully-qualified message name in the protobuf namespace. Similar to ",Object(i.b)("inlineCode",{parentName:"p"},"aux_message_options"),", we also have ",Object(i.b)("inlineCode",{parentName:"p"},"aux_enum_options"),", ",Object(i.b)("inlineCode",{parentName:"p"},"aux_enum_value_options")," and ",Object(i.b)("inlineCode",{parentName:"p"},"aux_field_options"),". See ",Object(i.b)("a",{parentName:"p",href:"https://github.com/scalapb/ScalaPB/tree/master/e2e/src/main/protobuf/scoped"},"example usage here"),". If the target is set ",Object(i.b)("inlineCode",{parentName:"p"},"*")," then the options will be\napplied to all the entities in the file or package (depending on the ",Object(i.b)("inlineCode",{parentName:"p"},"scope")," option)."),Object(i.b)("h2",{id:"primitive-wrappers"},"Primitive wrappers"),Object(i.b)("p",null,"In proto 3, unlike proto 2, primitives are not wrapped in an option by default.\nThe standard technique to obtain an optional primitive is to wrap it inside a\nmessage (since messages are provided inside an ",Object(i.b)("inlineCode",{parentName:"p"},"Option"),"). Google provides\nstandard wrappers to the primitive types in\n",Object(i.b)("a",{parentName:"p",href:"https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/wrappers.proto"},"wrappers.proto"),"."),Object(i.b)("p",null,Object(i.b)("inlineCode",{parentName:"p"},"primitive_wrappers")," is enabled by default for ScalaPB>=0.6.0. Whenever one\nof the standard wrappers is used, it will be mapped to ",Object(i.b)("inlineCode",{parentName:"p"},"Option[X]")," where ",Object(i.b)("inlineCode",{parentName:"p"},"X"),"\nis a primitive type. For example:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'syntax = "proto3";\n\nimport "google/protobuf/wrappers.proto";\n\nmessage MyMessage {\n google.protobuf.Int32Value my_int32 = 5;\n}\n')),Object(i.b)("p",null,"would generate"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-scala"},"case class MyMessage(myInt32: Option[Int]) extends ...\n")),Object(i.b)("p",null,"To disable primitive wrappers in a file:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'import "scalapb/scalapb.proto";\noption (scalapb.options) = {\n no_primitive_wrappers: true\n};\n')),Object(i.b)("p",null,"In versions of ScalaPB prior to 0.6.0, primitive wrappers had to be turned on\nmanually in each file:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'import "scalapb/scalapb.proto";\noption (scalapb.options) = {\n primitive_wrappers: true\n};\n')),Object(i.b)("h2",{id:"custom-base-traits-for-messages"},"Custom base traits for messages"),Object(i.b)("p",null,"Note: this option is available in ScalaPB 0.6.1 and later."),Object(i.b)("p",null,"ScalaPBs allows you to specify custom base traits to a generated case\nclass. This is useful when you have a few messages that share common fields\nand you would like to be able to access those fields through a single trait."),Object(i.b)("p",null,"Example:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'import "scalapb/scalapb.proto";\n\nmessage CustomerWithPhone {\n option (scalapb.message).extends = "com.thesamet.pb.BaseCustomer";\n\n optional string customer_id = 1;\n optional string name = 2;\n optional string phone = 3;\n}\n')),Object(i.b)("p",null,"In your code, define the base trait ",Object(i.b)("inlineCode",{parentName:"p"},"BaseCustomer")," and include any subset of the fields:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-scala"},"package com.thesamet.pb\n\ntrait BaseCustomer {\n def customerId: Option[String]\n def name: Option[String]\n}\n")),Object(i.b)("p",null,"You can specify any number of base traits for a message."),Object(i.b)("p",null,"It is also possible to make the generated companion classes extend a class\nor trait, by using the ",Object(i.b)("inlineCode",{parentName:"p"},"companion_extends")," option. For example:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'message MyMessage {\n option (scalapb.message).extends = "MySuperClass";\n option (scalapb.message).companion_extends = "MySuperCompanionClass";\n int32 n = 1;\n}\n')),Object(i.b)("p",null,"Will generate a case class that extends ",Object(i.b)("inlineCode",{parentName:"p"},"MySuperClass"),", and the companion\nobject will extend ",Object(i.b)("inlineCode",{parentName:"p"},"MySuperCompanionClass"),"."),Object(i.b)("h2",{id:"custom-base-traits-for-sealed-oneofs"},"Custom base traits for sealed oneofs"),Object(i.b)("p",null,"Since 0.9.0, you can use ",Object(i.b)("inlineCode",{parentName:"p"},"sealed_one_extends")," to define one or more base traits for a generated SealedOneof."),Object(i.b)("p",null,"Since 0.11.16, you can also add base traits to the empty case object using ",Object(i.b)("inlineCode",{parentName:"p"},"sealed_oneof_empty_extends"),"."),Object(i.b)("p",null,"Use the following options to"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'message MyEither {\n option (scalapb.message).sealed_oneof_extends = "MyBaseTrait";\n option (scalapb.message).sealed_oneof_empty_extends = "MyEmptyTrait";\n\n oneof sealed_value {\n Left left = 1;\n Right right = 2;\n }\n}\n')),Object(i.b)("p",null,"As of ScalaPB 0.11.11 you may also use following option to make the generated sealed oneof\ntrait ",Object(i.b)("a",{parentName:"p",href:"https://docs.scala-lang.org/overviews/core/value-classes.html"},"universal"),".\nIt may be useful when your sealed oneof variants are value-classes (e.g. extends ",Object(i.b)("inlineCode",{parentName:"p"},"AnyVal"),")"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-scala"},"trait MyBaseUniversalTrait extends Any\n")),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'message Left {\n option (scalapb.message).extends = "AnyVal";\n string error = 1;\n}\n\nmessage Right {\n option (scalapb.message).extends = "AnyVal";\n int32 value = 1;\n}\n\nmessage MyEither {\n option (scalapb.message) = {\n sealed_oneof_extends: ["Any", "MyBaseUniversalTrait"]\n };\n\n oneof sealed_value {\n Left left = 1;\n Right right = 2;\n }\n}\n')),Object(i.b)("h2",{id:"custom-base-traits-for-sealed-oneofs-companion-objects"},"Custom base traits for sealed oneofs companion objects"),Object(i.b)("blockquote",null,Object(i.b)("p",{parentName:"blockquote"},"Note: this option is available in ScalaPB 0.11.11 and later.")),Object(i.b)("p",null,"Use the following option to define one or more base traits for a generated SealedOneof companion object:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'message MyEither {\n option (scalapb.message).sealed_oneof_companion_extends = "MyBaseTrait";\n oneof sealed_value { /* ... */ }\n}\n')),Object(i.b)("h2",{id:"custom-base-traits-for-enums"},"Custom base traits for enums"),Object(i.b)("p",null,"In a similar fashion to custom base traits for messages, it is possible to\ndefine custom base traits for enum types, for the companion objects of enum\ntypes and even for specific values."),Object(i.b)("p",null,"For example:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'syntax = "proto2";\n\npackage enum_example;\n\nimport "scalapb/scalapb.proto";\n\nenum MyEnum {\n option (scalapb.enum_options).extends = "example.EnumOptions.EnumBase";\n option (scalapb.enum_options).companion_extends = "example.EnumOptions.EnumCompanionBase";\n Unknown = 0;\n V1 = 1 [(scalapb.enum_value).extends = "example.EnumOptions.ValueMixin"];\n V2 = 2;\n}\n')),Object(i.b)("p",null,"The generated code will look something like this:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-scala"},"sealed trait MyEnum extends GeneratedEnum\n with example.EnumOptions.EnumBase {\n /* ... */\n}\n\nobject MyEnum extends GeneratedEnumCompanion[MyEnum]\n with example.EnumOptions.EnumCompanionBase {\n case object Unknown extends MyEnum { /* ... */ }\n\n case object V1 extends MyEnum\n with example.EnumOptions.ValueMixin { /* ... */ }\n\n case object V2 extends MyEnum { /* ... */ }\n\n /* ... */\n}\n")),Object(i.b)("h2",{id:"custom-types"},"Custom types"),Object(i.b)("p",null,"You can customize the Scala type of any field. One use-case for this is when\nyou would like to use type-safe wrappers around primitive values to enforce unit\ncorrectness. For example, instead of using a raw integer for time fields, you can\nwrap them in a ",Object(i.b)("inlineCode",{parentName:"p"},"Seconds")," class."),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'import "scalapb/scalapb.proto";\n\nmessage Connection {\n optional int32 timeout = 1 [(scalapb.field).type = "mydomain.Seconds"];\n}\n')),Object(i.b)("p",null,"We would like to write code like this:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-scala"},"val c = Connection().update(_.timeout := Seconds(5))\n")),Object(i.b)("p",null,"How will ScalaPB know how to convert from the original type (",Object(i.b)("inlineCode",{parentName:"p"},"Integer"),") to the\ncustom type ",Object(i.b)("inlineCode",{parentName:"p"},"Seconds"),"? For each custom type you need to define an implicit\n",Object(i.b)("inlineCode",{parentName:"p"},"TypeMapper")," that will tell ScalaPB how to convert between the custom type and\nthe base Scala type. A good place to define this implicit is in the companion\nclass for your custom type, since the Scala compiler will look for a\ntypemapper there by default. If your typemapper is defined elsewhere, you\nwill need to import it manually by using the ",Object(i.b)("inlineCode",{parentName:"p"},"import")," file-level option."),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-scala"},"package mydomain\n\ncase class Seconds(v: Int) extends AnyVal\n\nobject Seconds {\n implicit val typeMapper: TypeMapper[Int, Seconds] = TypeMapper(Seconds.apply)(_.v)\n}\n")),Object(i.b)("p",null,Object(i.b)("inlineCode",{parentName:"p"},"TypeMapper")," takes two function parameters. The first converts from the original type to\nthe custom type. The second function converts from the custom type to the\noriginal type."),Object(i.b)("p",null,"In addition to primitive values, you can customize enums and messages as well."),Object(i.b)("p",null,"For more examples, see:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",{parentName:"li",href:"https://github.com/scalapb/ScalaPB/blob/master/e2e-withjava/src/main/protobuf/custom_types.proto"},Object(i.b)("inlineCode",{parentName:"a"},"custom_types.proto"))),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",{parentName:"li",href:"https://github.com/scalapb/ScalaPB/blob/master/e2e-withjava/src/main/scala/com/thesamet/pb/PersonId.scala"},Object(i.b)("inlineCode",{parentName:"a"},"PersonId.scala"))),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",{parentName:"li",href:"https://github.com/scalapb/ScalaPB/blob/master/e2e/src/test/scala/CustomTypesSpec.scala"},Object(i.b)("inlineCode",{parentName:"a"},"CustomTypesSpec.scala")))),Object(i.b)("p",null,"If you have a TypeMapper that maps a generated type into a type you don't own\n(such as ",Object(i.b)("inlineCode",{parentName:"p"},"String"),", or a third-party class) then you don't have access to the\ncompanion object to define the typemapper in. Instead, you can place the\ntypemapper in one of the parent package objects of the generated code. For\nexample, if you want to map an enum to a string, and the message containing it\ngoes into the ",Object(i.b)("inlineCode",{parentName:"p"},"a.b.c")," package, you can define the type mapper like this:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-scala"},"// src/main/scala/a/b/c/package.scala:\npackage a.b\n\npackage object c {\n implicit val segmentType: TypeMapper[SegmentType, String] =\n TypeMapper[SegmentType, String](_.name)(SegmentType.fromName(_).get)\n}\n")),Object(i.b)("h2",{id:"message-level-custom-type-and-boxing"},"Message-level custom type and boxing"),Object(i.b)("p",null,"In the previous section you saw how to customize the type generated for a\nspecific field. ScalaPB also lets you specify a custom type at the message\nlevel. When ",Object(i.b)("inlineCode",{parentName:"p"},"type")," is set at the message level, that type is used for all the\nfields that use that message. This eliminates the need to specify ",Object(i.b)("inlineCode",{parentName:"p"},"type")," on each field\nof this type."),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'// duration.proto\nsyntax = "proto3";\n\npackage mytypes;\n\nimport "scalapb/scalapb.proto";\n\nmessage Duration {\n option (scalapb.message).type = "mytypes.MyDurationClass";\n int32 seconds = 1;\n}\n')),Object(i.b)("p",null,"In a Scala file define an implicit mapper:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-scala"},"import scalapb.TypeMapper\nimport mytypes.duration.Duration\n\ncase class MyDurationClass(seconds: Int)\n\nobject MyDurationClass {\n implicit val tm: TypeMapper[Duration, MyDurationClass] = TypeMapper[Duration, MyDurationClass] {\n d: Duration => MyDurationClass(d.seconds) } {\n m: MyDurationClass => Duration(m.seconds)\n }\n}\n")),Object(i.b)("p",null,"Now, each time you reference ",Object(i.b)("inlineCode",{parentName:"p"},"Duration")," in a proto file, the generated field in Scala code\nwill be of type ",Object(i.b)("inlineCode",{parentName:"p"},"MyDuration"),":"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'syntax = "proto3";\n\npackage mytypes;\n\nimport "scalapb/scalapb.proto";\nimport "duration.proto";\n\nmessage Usage {\n Duration dd = 1; // will become dd: Option[MyDuration]\n repeated Duration ds = 2; // will become ds: Seq[MyDuration]\n\n // You can eliminate the boxing of an optional field in an Option by using\n // no_box\n Duration dd_nobox = 3 [(scalapb.field).no_box = true]; // will become ddNoBox: MyDuration\n}\n')),Object(i.b)("p",null,"If you do not want any instance of your message to be boxed (regardless if it\nhas a custom type), you can set ",Object(i.b)("inlineCode",{parentName:"p"},"no_box")," at the message-level:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'// duration_nobox.proto\nsyntax = "proto3";\n\npackage mytypes;\n\nimport "scalapb/scalapb.proto";\n\nmessage Duration {\n option (scalapb.message).type = "mytypes.MyDurationType";\n option (scalapb.message).no_box = true; // do not wrap in Option\n int32 seconds = 1;\n}\n')),Object(i.b)("p",null,"Then when this message is used, it will not be wrapped in an ",Object(i.b)("inlineCode",{parentName:"p"},"Option"),". If\n",Object(i.b)("inlineCode",{parentName:"p"},"no_box")," is specified at the field level, it overrides the value specified at\nthe message level."),Object(i.b)("h2",{id:"custom-types-on-maps"},"Custom types on maps"),Object(i.b)("p",null,"Since version 0.6.0 it is possible to customize the key and value types of\nmaps. Like the custom types described above you will need to have a ",Object(i.b)("inlineCode",{parentName:"p"},"TypeMapper"),"\nfor the custom type."),Object(i.b)("p",null,"Example:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'message CustomMaps {\n // Will generate Map[String, com.thesamet.pb.Years]\n map<string, int32> string_to_year = 1 [\n (scalapb.field).value_type = "com.thesamet.pb.Years"];\n\n // Will generate Map[PersonId, Int]\n map<string, int32> person_to_int = 2 [\n (scalapb.field).key_type = "com.thesamet.pb.PersonId"];\n\n // Will generate Map[PersonId, com.thesamet.pb.Years]\n map<string, int32> person_to_year = 3 [\n (scalapb.field).key_type = "com.thesamet.pb.PersonId",\n (scalapb.field).value_type = "com.thesamet.pb.Years"];\n}\n')),Object(i.b)("p",null,"Example: see ",Object(i.b)("inlineCode",{parentName:"p"},"CustomMaps")," in ",Object(i.b)("a",{parentName:"p",href:"https://github.com/scalapb/ScalaPB/blob/master/e2e-withjava/src/main/protobuf/maps.proto"},"maps.proto")),Object(i.b)("p",null,"You can also customize the collection type used for a map. See the next\nsection for details."),Object(i.b)("h2",{id:"custom-collection-types"},"Custom collection types"),Object(i.b)("p",null,"By default, ScalaPB compiles repeated fields into a ",Object(i.b)("inlineCode",{parentName:"p"},"Seq[T]"),". When a message\nis parsed from bytes, the default implementation instantiates a ",Object(i.b)("inlineCode",{parentName:"p"},"Vector[T]"),",\nwhich is a subtype of ",Object(i.b)("inlineCode",{parentName:"p"},"Seq[T]"),". You can instruct ScalaPB to use a different\ncollection type for one field by specifying the ",Object(i.b)("inlineCode",{parentName:"p"},"collection_type")," option. You\ncan also specify a ",Object(i.b)("inlineCode",{parentName:"p"},"collection_type")," for the entire proto file by specifying a\n",Object(i.b)("inlineCode",{parentName:"p"},"collection_type")," at the file-level."),Object(i.b)("p",null,"If both are defined then the field-level setting wins."),Object(i.b)("p",null,"Similar to ",Object(i.b)("inlineCode",{parentName:"p"},"collection_type"),", we have ",Object(i.b)("inlineCode",{parentName:"p"},"map_type")," for map types. By default,\nScalaPB generates ",Object(i.b)("inlineCode",{parentName:"p"},"scala.collection.immutable.Map")," for maps, and you can\ncustomize it at the field level, or file-level by specifying a ",Object(i.b)("inlineCode",{parentName:"p"},"map_type"),"\noption."),Object(i.b)("p",null,Object(i.b)("inlineCode",{parentName:"p"},"map_type")," was introduced in ScalaPB 0.8.5."),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'import "scalapb/scalapb.proto";\n\noption (scalapb.options) = {\n collection_type: "Set"\n};\n\nmessage CollTest {\n // Will generate Set[Int] due to file-level option.\n repeated int32 rep1 = 1;\n\n // Will generate an Array[String]\n repeated string rep2 = 2 [\n (scalapb.field).collection_type="Array"];\n\n // Will generate Seq[collection.immutable.Seq]\n repeated bool rep3 = 3 [\n (scalapb.field).collection_type="collection.immutable.Seq"];\n\n map<int32, string> my_map = 4 [\n (scalapb.field).map_type="collection.mutable.Map"];\n}\n')),Object(i.b)("p",null,"Note on mutable collection: ScalaPB assumes that all data is immutable. For example, the result\nof ",Object(i.b)("inlineCode",{parentName:"p"},"serializedSize")," is cached in a private field. When choosing mutable collections, you must be\ncareful not to mutate any collection after it has been passed to any message, or you might get some\nsurprising results!"),Object(i.b)("p",null,"Note: using ",Object(i.b)("inlineCode",{parentName:"p"},"Array")," is not supported along with Java conversions."),Object(i.b)("p",null,"Note: Most Scala collections can be used with this feature. If you are trying\nto implement your own collection type, it may be useful to check ",Object(i.b)("inlineCode",{parentName:"p"},"MyVector"),"\nand ",Object(i.b)("inlineCode",{parentName:"p"},"MyMap"),", the simplest custom collection that is compatible with ScalaPB:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",{parentName:"li",href:"https://github.com/scalapb/ScalaPB/blob/master/e2e-withjava/src/main/scala-2.13/com/thesamet/pb/MyVector.scala"},"MyVector.scala")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",{parentName:"li",href:"https://github.com/scalapb/ScalaPB/blob/master/e2e-withjava/src/main/scala-2.13/com/thesamet/pb/MyMap.scala"},"MyMap.scala")),Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",{parentName:"li",href:"https://github.com/scalapb/ScalaPB/blob/master/e2e-withjava/src/main/protobuf/collection_types.proto"},"collection_types.proto"))),Object(i.b)("h2",{id:"custom-names"},"Custom names"),Object(i.b)("p",null,"Sometimes it may be useful to manually specify the name of a field in the\ngenerated code. For example, if you have a field named ",Object(i.b)("inlineCode",{parentName:"p"},"hash_code"),", then the\ncamel-case version of it would be ",Object(i.b)("inlineCode",{parentName:"p"},"hashCode"),". Since that name would conflict with\nthe ",Object(i.b)("a",{parentName:"p",href:"https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()"},Object(i.b)("inlineCode",{parentName:"a"},"hashCode()")," method"),"\nwe inherit from Java, ScalaPB issues an error. You can tell ScalaPB to use an\nalternative name by using the ",Object(i.b)("inlineCode",{parentName:"p"},"scala_name")," option:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'optional string hash_code = 1 [(scalapb.field).scala_name = "myHashCode"];\n')),Object(i.b)("p",null,"It is also possible to customize the Scala name of an enum value:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'enum MyEnum {\n DEFAULT = 0;\n FOO = 1 [(scalapb.enum_value).scala_name = "Bar"];\n}\n')),Object(i.b)("p",null,"The same customization can be applied to ",Object(i.b)("inlineCode",{parentName:"p"},"oneof")," fields:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'oneof notify {\n option (scalapb.oneof).scala_name = "myNotify";\n\n string foo = 1;\n int32 bar = 2;\n}\n')),Object(i.b)("h2",{id:"adding-annotations"},"Adding annotations"),Object(i.b)("p",null,"Since ScalaPB 0.6.3, you can add annotations to the generated case classes like this:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'message BarMessage {\n option (scalapb.message).annotations = "@mypackage.CustomAnnotation";\n option (scalapb.message).annotations = "@mypackage.CustomAnnotation1";\n option (scalapb.message).annotations = "@mypackage.CustomAnnotation2";\n}\n')),Object(i.b)("p",null,"In ScalaPB 0.7.0, you can add annotations to the companion object of a\nmessage and to individual fields:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'message BarMessage {\n option (scalapb.message).companion_annotations = "@mypackage.AnotherAnnotation2";\n\n optional string x = 1 [\n (scalapb.field).annotations = \'@deprecated("Will be gone", "1.0")\'\n ];\n}\n')),Object(i.b)("p",null,"In ScalaPB 0.10.9, you can also add annotations to the auto generated unknownFields field:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'message BarMessage {\n option (scalapb.message).unknown_field_annotations = "@annotation1";\n}\n')),Object(i.b)("p",null,"In ScalaPB 0.11.4, you can also add annotations to the enum values and the ",Object(i.b)("inlineCode",{parentName:"p"},"Unrecognized")," case class:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'enum BarEnum {\n option (scalapb.enum_options) = "@annotation"\n}\n\nenum BarEnum {\n // every value will have the annotation added.\n option (scalapb.enum_options).base_annotations = "@annotation1";\n // only known values (case objects) will have the annotation added.\n option (scalapb.enum_options).recognized_annotations = "@annotation2";\n // only the unrecognized case class will have the annotation added.\n option (scalapb.enum_options).unrecognized_annotations = "@annotation3";\n // only this value (case object) will have the annotation added.\n BarValue = 1 [(scalapb.enum_value).annotations = "@annotation4"];\n}\n')),Object(i.b)("h2",{id:"adding-derives-clause"},"Adding derives clause"),Object(i.b)("p",null,"In ScalaPB 0.11.14, it is possible to add a ",Object(i.b)("inlineCode",{parentName:"p"},"derives")," clause to generated messages and\nsealed oneofs:"),Object(i.b)("pre",null,Object(i.b)("code",{parentName:"pre",className:"language-protobuf"},'message Foo {\n option (scalapb.message).derives = "yourpkg.Show";\n ...\n}}}\n\nmessage Expr {\n option (scalapb.message).sealed_oneof_derives = "yourpkg.Show";\n oneof sealed_value {\n ...\n }\n}\n')))}b.isMDXComponent=!0}}]);