Skip to content

Commit d93a990

Browse files
authored
feat: removing private from typemapper (#1674)
* feat: removing private from typemapper * feat: public_constructor_parameters flag
1 parent b8a7cd1 commit d93a990

File tree

9 files changed

+170
-66
lines changed

9 files changed

+170
-66
lines changed

compiler-plugin/src/main/scala/scalapb/compiler/DescriptorImplicits.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,8 @@ class DescriptorImplicits private[compiler] (
933933

934934
def emitScala3Sources: Boolean = scalaOptions.getScala3Sources || params.scala3Sources
935935

936+
def generatePublicConstructorParameters: Boolean = scalaOptions.getPublicConstructorParameters
937+
936938
def V: ScalaCompatConstants = new ScalaCompatConstants(emitScala3Sources)
937939

938940
def javaPackageAsSymbol: String =

compiler-plugin/src/main/scala/scalapb/compiler/ProtobufGenerator.scala

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class ProtobufGenerator(
1919
params: GeneratorParams,
2020
implicits: DescriptorImplicits
2121
) {
22+
2223
import implicits._
2324
import DescriptorImplicits.AsSymbolExtension
2425
import ProtobufGenerator._
@@ -157,6 +158,7 @@ class ProtobufGenerator(
157158
def defaultValueForGet(field: FieldDescriptor, uncustomized: Boolean = false) = {
158159
// Needs to be 'def' and not val since for some of the cases it's invalid to call it.
159160
def defaultValue = field.getDefaultValue
161+
160162
val baseDefaultValue: String = field.getJavaType match {
161163
case FieldDescriptor.JavaType.INT => defaultValue.toString
162164
case FieldDescriptor.JavaType.LONG => defaultValue.toString + "L"
@@ -257,6 +259,7 @@ class ProtobufGenerator(
257259
// TODO(thesamet): if both unit conversions are NoOp, we can omit the map call.
258260
def unitConversion(n: String, field: FieldDescriptor) =
259261
javaToScalaConversion(field).apply(n, EnclosingType.None)
262+
260263
val upperJavaName =
261264
if (
262265
field.mapType.valueField.isEnum && !field.mapType.valueField.legacyEnumFieldTreatedAsClosed
@@ -957,7 +960,8 @@ class ProtobufGenerator(
957960
}
958961

959962
def generateMessageLens(message: Descriptor)(printer: FunctionalPrinter): FunctionalPrinter = {
960-
val className = message.scalaType.name
963+
val className = message.scalaType.name
964+
961965
def lensType(s: String) = s"_root_.scalapb.lenses.Lens[UpperPB, $s]"
962966

963967
printer
@@ -1011,7 +1015,8 @@ class ProtobufGenerator(
10111015
}
10121016

10131017
def generateTypeMappers(
1014-
fields: Seq[FieldDescriptor]
1018+
fields: Seq[FieldDescriptor],
1019+
generatePublicConstructorParameters: Boolean
10151020
)(printer: FunctionalPrinter): FunctionalPrinter = {
10161021
val customizedFields: Seq[(FieldDescriptor, String)] = for {
10171022
field <- fields
@@ -1020,13 +1025,15 @@ class ProtobufGenerator(
10201025

10211026
printer
10221027
.print(customizedFields) { case (printer, (field, customType)) =>
1023-
val modifier =
1024-
if (field.getFile().scalaPackage.fullName.isEmpty) "private"
1025-
else s"private[${field.getFile().scalaPackage.fullName.split('.').last}]"
1028+
val modifier = {
1029+
if (generatePublicConstructorParameters) ""
1030+
else if (field.getFile().scalaPackage.fullName.isEmpty) "private "
1031+
else s"private[${field.getFile().scalaPackage.fullName.split('.').last}] "
1032+
}
10261033
printer
10271034
.add("@transient")
10281035
.add(
1029-
s"$modifier val ${field.typeMapperValName}: _root_.scalapb.TypeMapper[${field.baseSingleScalaTypeName}, ${customType}] = implicitly[_root_.scalapb.TypeMapper[${field.baseSingleScalaTypeName}, ${customType}]]"
1036+
s"${modifier}val ${field.typeMapperValName}: _root_.scalapb.TypeMapper[${field.baseSingleScalaTypeName}, ${customType}] = implicitly[_root_.scalapb.TypeMapper[${field.baseSingleScalaTypeName}, ${customType}]]"
10301037
)
10311038
}
10321039
}
@@ -1314,7 +1321,12 @@ class ProtobufGenerator(
13141321
.print(message.getExtensions.asScala)(printExtension)
13151322
.when(message.generateLenses)(generateMessageLens(message))
13161323
.call(generateFieldNumbers(message))
1317-
.call(generateTypeMappers(message.fields ++ message.getExtensions.asScala))
1324+
.call(
1325+
generateTypeMappers(
1326+
message.fields ++ message.getExtensions.asScala,
1327+
message.getFile.generatePublicConstructorParameters
1328+
)
1329+
)
13181330
.call(generateCollectionAdapters(message.fields ++ message.getExtensions.asScala))
13191331
.when(message.isMapEntry)(generateTypeMappersForMapEntry(message))
13201332
.call(generateNoDefaultArgsFactory(message))
@@ -1650,7 +1662,12 @@ class ProtobufGenerator(
16501662
.call(generateMessagesCompanions(file)(_))
16511663
.call(generateFileDescriptor(file)(_))
16521664
.print(file.getExtensions.asScala)(printExtension(_, _))
1653-
.call(generateTypeMappers(file.getExtensions.asScala.toSeq))
1665+
.call(
1666+
generateTypeMappers(
1667+
file.getExtensions.asScala.toSeq,
1668+
file.generatePublicConstructorParameters
1669+
)
1670+
)
16541671
.outdent
16551672
.add("}")
16561673
}

docs/src/main/markdown/customizations.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ option (scalapb.options) = {
5757
enum_strip_prefix: false
5858
bytes_type: "scodec.bits.ByteVector"
5959
scala3_sources: false
60+
public_constructor_parameters: false
6061
};
6162
```
6263

@@ -134,6 +135,10 @@ enums to a single Scala file.
134135

135136
- 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 `-source feature` on Scala 3 or with `-Xsource:3` on Scala 2.13, set `scala3_sources` to `true` or pass the `scala3_sources` generator parameter.
136137

138+
- Use `public_constructor_parameters` to make constructor parameters public, including defaults and TypeMappers.
139+
This is helpful for automated schema derivation with e.g. `magnolia` when trying to also derive default fields by
140+
using the compiler flag `-Yretain-trees`. Without this flag, the companion object's `_typemapper_*` fields are private.
141+
137142
## Package-scoped options
138143

139144
Note: this option is available in ScalaPB 0.8.2 and later.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
syntax = "proto3";
2+
3+
package com.thesamet.proto.e2e;
4+
5+
import "scalapb/scalapb.proto";
6+
7+
option (scalapb.options) = {
8+
public_constructor_parameters: true,
9+
preserve_unknown_fields: false,
10+
single_file: true,
11+
import: "com.thesamet.proto.e2e.TypeMappers.enumMapper",
12+
aux_field_options : [
13+
{
14+
target: "com.thesamet.proto.e2e.NestedExampleEvent.action"
15+
options: {
16+
type: "String"
17+
}}
18+
],
19+
};
20+
21+
message NestedExampleEvent {
22+
string id = 1;
23+
Action action = 2;
24+
enum Action {
25+
Undefined = 0;
26+
Allow = 1;
27+
Deny = 2;
28+
}
29+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.thesamet.proto.e2e
2+
3+
import scalapb.{GeneratedEnumCompanion, TypeMapper}
4+
5+
object TypeMappers {
6+
implicit def enumMapper[A <: scalapb.GeneratedEnum](implicit ec: GeneratedEnumCompanion[A]): TypeMapper[A, String] = TypeMapper[A, String](_.name)(ec.fromName(_).get)
7+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import org.scalatest.funspec.AnyFunSpec
2+
import org.scalatest.matchers.must.Matchers
3+
import com.thesamet.proto.e2e.issue1664.NestedExampleEvent
4+
5+
class Issue1664Spec extends AnyFunSpec with Matchers {
6+
7+
it("issue1664:public_constructor_parameters") {
8+
// Without public_constructor_parameters, this is inaccessible
9+
NestedExampleEvent._typemapper_action.toBase("Allow") mustBe NestedExampleEvent.Action.Allow
10+
}
11+
12+
}

protobuf/scalapb/scalapb.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ message ScalaPbOptions {
184184
// Generate sources that are compatible with Scala 3
185185
optional bool scala3_sources = 28;
186186

187+
// Makes constructor parameters public, including defaults and TypeMappers.
188+
optional bool public_constructor_parameters = 29;
189+
187190
// For use in tests only. Inhibit Java conversions even when when generator parameters
188191
// request for it.
189192
optional bool test_only_no_java_conversions = 999;

scalapb-runtime/src/main/scala/scalapb/options/ScalaPbOptions.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ package scalapb.options
7979
* If true, getters will be generated.
8080
* @param scala3Sources
8181
* Generate sources that are compatible with Scala 3
82+
* @param publicConstructorParameters
83+
* Makes constructor parameters public, including defaults and TypeMappers.
8284
* @param testOnlyNoJavaConversions
8385
* For use in tests only. Inhibit Java conversions even when when generator parameters
8486
* request for it.
@@ -113,6 +115,7 @@ final case class ScalaPbOptions(
113115
ignoreAllTransformations: _root_.scala.Option[_root_.scala.Boolean] = _root_.scala.None,
114116
getters: _root_.scala.Option[_root_.scala.Boolean] = _root_.scala.None,
115117
scala3Sources: _root_.scala.Option[_root_.scala.Boolean] = _root_.scala.None,
118+
publicConstructorParameters: _root_.scala.Option[_root_.scala.Boolean] = _root_.scala.None,
116119
testOnlyNoJavaConversions: _root_.scala.Option[_root_.scala.Boolean] = _root_.scala.None,
117120
unknownFields: _root_.scalapb.UnknownFieldSet = _root_.scalapb.UnknownFieldSet.empty
118121
) extends scalapb.GeneratedMessage with scalapb.lenses.Updatable[ScalaPbOptions] with _root_.scalapb.ExtendableMessage[ScalaPbOptions] {
@@ -232,6 +235,10 @@ final case class ScalaPbOptions(
232235
val __value = scala3Sources.get
233236
__size += _root_.com.google.protobuf.CodedOutputStream.computeBoolSize(28, __value)
234237
};
238+
if (publicConstructorParameters.isDefined) {
239+
val __value = publicConstructorParameters.get
240+
__size += _root_.com.google.protobuf.CodedOutputStream.computeBoolSize(29, __value)
241+
};
235242
if (testOnlyNoJavaConversions.isDefined) {
236243
val __value = testOnlyNoJavaConversions.get
237244
__size += _root_.com.google.protobuf.CodedOutputStream.computeBoolSize(999, __value)
@@ -371,6 +378,10 @@ final case class ScalaPbOptions(
371378
val __m = __v
372379
_output__.writeBool(28, __m)
373380
};
381+
publicConstructorParameters.foreach { __v =>
382+
val __m = __v
383+
_output__.writeBool(29, __m)
384+
};
374385
testOnlyNoJavaConversions.foreach { __v =>
375386
val __m = __v
376387
_output__.writeBool(999, __m)
@@ -469,6 +480,9 @@ final case class ScalaPbOptions(
469480
def getScala3Sources: _root_.scala.Boolean = scala3Sources.getOrElse(false)
470481
def clearScala3Sources: ScalaPbOptions = copy(scala3Sources = _root_.scala.None)
471482
def withScala3Sources(__v: _root_.scala.Boolean): ScalaPbOptions = copy(scala3Sources = Option(__v))
483+
def getPublicConstructorParameters: _root_.scala.Boolean = publicConstructorParameters.getOrElse(false)
484+
def clearPublicConstructorParameters: ScalaPbOptions = copy(publicConstructorParameters = _root_.scala.None)
485+
def withPublicConstructorParameters(__v: _root_.scala.Boolean): ScalaPbOptions = copy(publicConstructorParameters = Option(__v))
472486
def getTestOnlyNoJavaConversions: _root_.scala.Boolean = testOnlyNoJavaConversions.getOrElse(false)
473487
def clearTestOnlyNoJavaConversions: ScalaPbOptions = copy(testOnlyNoJavaConversions = _root_.scala.None)
474488
def withTestOnlyNoJavaConversions(__v: _root_.scala.Boolean): ScalaPbOptions = copy(testOnlyNoJavaConversions = Option(__v))
@@ -504,6 +518,7 @@ final case class ScalaPbOptions(
504518
case 26 => ignoreAllTransformations.orNull
505519
case 27 => getters.orNull
506520
case 28 => scala3Sources.orNull
521+
case 29 => publicConstructorParameters.orNull
507522
case 999 => testOnlyNoJavaConversions.orNull
508523
}
509524
}
@@ -538,6 +553,7 @@ final case class ScalaPbOptions(
538553
case 26 => ignoreAllTransformations.map(_root_.scalapb.descriptors.PBoolean(_)).getOrElse(_root_.scalapb.descriptors.PEmpty)
539554
case 27 => getters.map(_root_.scalapb.descriptors.PBoolean(_)).getOrElse(_root_.scalapb.descriptors.PEmpty)
540555
case 28 => scala3Sources.map(_root_.scalapb.descriptors.PBoolean(_)).getOrElse(_root_.scalapb.descriptors.PEmpty)
556+
case 29 => publicConstructorParameters.map(_root_.scalapb.descriptors.PBoolean(_)).getOrElse(_root_.scalapb.descriptors.PEmpty)
541557
case 999 => testOnlyNoJavaConversions.map(_root_.scalapb.descriptors.PBoolean(_)).getOrElse(_root_.scalapb.descriptors.PEmpty)
542558
}
543559
}
@@ -577,6 +593,7 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options.
577593
var __ignoreAllTransformations: _root_.scala.Option[_root_.scala.Boolean] = _root_.scala.None
578594
var __getters: _root_.scala.Option[_root_.scala.Boolean] = _root_.scala.None
579595
var __scala3Sources: _root_.scala.Option[_root_.scala.Boolean] = _root_.scala.None
596+
var __publicConstructorParameters: _root_.scala.Option[_root_.scala.Boolean] = _root_.scala.None
580597
var __testOnlyNoJavaConversions: _root_.scala.Option[_root_.scala.Boolean] = _root_.scala.None
581598
var `_unknownFields__`: _root_.scalapb.UnknownFieldSet.Builder = null
582599
var _done__ = false
@@ -640,6 +657,8 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options.
640657
__getters = _root_.scala.Option(_input__.readBool())
641658
case 224 =>
642659
__scala3Sources = _root_.scala.Option(_input__.readBool())
660+
case 232 =>
661+
__publicConstructorParameters = _root_.scala.Option(_input__.readBool())
643662
case 7992 =>
644663
__testOnlyNoJavaConversions = _root_.scala.Option(_input__.readBool())
645664
case tag =>
@@ -678,6 +697,7 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options.
678697
ignoreAllTransformations = __ignoreAllTransformations,
679698
getters = __getters,
680699
scala3Sources = __scala3Sources,
700+
publicConstructorParameters = __publicConstructorParameters,
681701
testOnlyNoJavaConversions = __testOnlyNoJavaConversions,
682702
unknownFields = if (_unknownFields__ == null) _root_.scalapb.UnknownFieldSet.empty else _unknownFields__.result()
683703
)
@@ -714,6 +734,7 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options.
714734
ignoreAllTransformations = __fieldsMap.get(scalaDescriptor.findFieldByNumber(26).get).flatMap(_.as[_root_.scala.Option[_root_.scala.Boolean]]),
715735
getters = __fieldsMap.get(scalaDescriptor.findFieldByNumber(27).get).flatMap(_.as[_root_.scala.Option[_root_.scala.Boolean]]),
716736
scala3Sources = __fieldsMap.get(scalaDescriptor.findFieldByNumber(28).get).flatMap(_.as[_root_.scala.Option[_root_.scala.Boolean]]),
737+
publicConstructorParameters = __fieldsMap.get(scalaDescriptor.findFieldByNumber(29).get).flatMap(_.as[_root_.scala.Option[_root_.scala.Boolean]]),
717738
testOnlyNoJavaConversions = __fieldsMap.get(scalaDescriptor.findFieldByNumber(999).get).flatMap(_.as[_root_.scala.Option[_root_.scala.Boolean]])
718739
)
719740
case _ => throw new RuntimeException("Expected PMessage")
@@ -773,6 +794,7 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options.
773794
ignoreAllTransformations = _root_.scala.None,
774795
getters = _root_.scala.None,
775796
scala3Sources = _root_.scala.None,
797+
publicConstructorParameters = _root_.scala.None,
776798
testOnlyNoJavaConversions = _root_.scala.None
777799
)
778800
/** Whether to apply the options only to this file, or for the entire package (and its subpackages)
@@ -1512,6 +1534,8 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options.
15121534
def optionalGetters: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Option[_root_.scala.Boolean]] = field(_.getters)((c_, f_) => c_.copy(getters = f_))
15131535
def scala3Sources: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Boolean] = field(_.getScala3Sources)((c_, f_) => c_.copy(scala3Sources = _root_.scala.Option(f_)))
15141536
def optionalScala3Sources: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Option[_root_.scala.Boolean]] = field(_.scala3Sources)((c_, f_) => c_.copy(scala3Sources = f_))
1537+
def publicConstructorParameters: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Boolean] = field(_.getPublicConstructorParameters)((c_, f_) => c_.copy(publicConstructorParameters = _root_.scala.Option(f_)))
1538+
def optionalPublicConstructorParameters: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Option[_root_.scala.Boolean]] = field(_.publicConstructorParameters)((c_, f_) => c_.copy(publicConstructorParameters = f_))
15151539
def testOnlyNoJavaConversions: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Boolean] = field(_.getTestOnlyNoJavaConversions)((c_, f_) => c_.copy(testOnlyNoJavaConversions = _root_.scala.Option(f_)))
15161540
def optionalTestOnlyNoJavaConversions: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Option[_root_.scala.Boolean]] = field(_.testOnlyNoJavaConversions)((c_, f_) => c_.copy(testOnlyNoJavaConversions = f_))
15171541
}
@@ -1543,6 +1567,7 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options.
15431567
final val IGNORE_ALL_TRANSFORMATIONS_FIELD_NUMBER = 26
15441568
final val GETTERS_FIELD_NUMBER = 27
15451569
final val SCALA3_SOURCES_FIELD_NUMBER = 28
1570+
final val PUBLIC_CONSTRUCTOR_PARAMETERS_FIELD_NUMBER = 29
15461571
final val TEST_ONLY_NO_JAVA_CONVERSIONS_FIELD_NUMBER = 999
15471572
def of(
15481573
packageName: _root_.scala.Option[_root_.scala.Predef.String],
@@ -1573,6 +1598,7 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options.
15731598
ignoreAllTransformations: _root_.scala.Option[_root_.scala.Boolean],
15741599
getters: _root_.scala.Option[_root_.scala.Boolean],
15751600
scala3Sources: _root_.scala.Option[_root_.scala.Boolean],
1601+
publicConstructorParameters: _root_.scala.Option[_root_.scala.Boolean],
15761602
testOnlyNoJavaConversions: _root_.scala.Option[_root_.scala.Boolean]
15771603
): _root_.scalapb.options.ScalaPbOptions = _root_.scalapb.options.ScalaPbOptions(
15781604
packageName,
@@ -1603,6 +1629,7 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options.
16031629
ignoreAllTransformations,
16041630
getters,
16051631
scala3Sources,
1632+
publicConstructorParameters,
16061633
testOnlyNoJavaConversions
16071634
)
16081635
// @@protoc_insertion_point(GeneratedMessageCompanion[scalapb.ScalaPbOptions])

0 commit comments

Comments
 (0)