Scala scalapb GeneratedMessageCompanion- do not conform to trait GeneratedMessageCompanion's - scala

I am trying to generate Scala proto buff classes using Scalapb (https://scalapb.github.io/docs/scalapbc/). I am able to generate scala files but getting below error.
type arguments [com.huawei.utility.protobuff.embedtoRedis.embedtoRedis] do not conform to trait GeneratedMessageCompanion's type parameter bounds [A <: scalapb.GeneratedMessage with scalapb.Message[A]]
Sample.proto
syntax = "proto2";
package protobuff;
message embedtoRedis {
required int32 StudentID = 1;
repeated float StudentTitle = 2;
required string Class = 3;
optional string color = 4;
required string Type = 5;
}
After compiling using below command, i got two scala classes.
ScalaPbc\scalapbc-0.11.1\bin>scalapbc.bat -v3.5.1 --scala_out=C:\Users\satheesh\Documents\ScalaPbc\new sample.proto
Scala classes:
EmbedtoRedis.scala
SampleProto.scala
I am facing the issue in embedToRedis.scala in the following lines.
object embedtoRedis extends scalapb.GeneratedMessageCompanion[protobuff.sample.embedtoRedis] {
implicit def messageCompanion: scalapb.GeneratedMessageCompanion[protobuff.sample.embedtoRedis] = this
def parseFrom(`_input__`: _root_.com.google.protobuf.CodedInputStream): protobuff.sample.embedtoRedis = {
var __requiredFields0: _root_.scala.Long = 0x7L
var __studentID: _root_.scala.Int = 0
val __studentTitle: _root_.scala.collection.immutable.VectorBuilder[_root_.scala.Float] = new _root_.scala.collection.immutable.VectorBuilder[_root_.scala.Float]
var ___class: _root_.scala.Predef.String = ""
var __color: _root_.scala.Option[_root_.scala.Predef.String] = _root_.scala.None
var __type: _root_.scala.Predef.String = ""
Error:
type arguments [com.huawei.utility.protobuff.embedtoRedis.embedtoRedis] do not conform to trait GeneratedMessageCompanion's type parameter bounds [A <: scalapb.GeneratedMessage with scalapb.Message[A]]
Can you please help if i am missing something?

The version of ScalaPB used to generate the source files does not match the version you use at compile time. Check that the versions of scalapbc tool (standalone source generator) and scalapb-runtime match.

Related

How to generate any protobuf Enum as String with only one TypeMapper?

For instance, I have some enums in my proto schema:
enum E1 {
UNKNOWN = 0;
OPTION_1 = 1;
OPTION_2 = 2;
OPTION_3 = 3;
}
enum E2 {
UNKNOWN = 0;
ANOTHER_OPTION_1 = 1;
ANOTHER_OPTION_2 = 2;
ANOTHER_OPTION_3 = 3;
}
message M {
E1 my_enum_1 = 1;
E2 my_enum_2 = 2;
}
I can generate scala classes with strings instead of enums by providing scalaPB TypeMappers:
TypeMapper(_.name)(E1.fromName(_).get)
TypeMapper(_.name)(E2.fromName(_).get)
But I don't want to copypaste same TypeMappers for any single Enum
Is there any way to make only one TypeMapper for all enums with scalaPB?
Yes, this can be done.
If you want to make ScalaPB use String for all enums within a package, you can add package-scoped options file to tell ScalaPB to set the scala-type for each enum to a String using field transformations:
// options.proto:
syntax = "proto3";
import "scalapb/scalapb.proto";
option (scalapb.options) = {
scope: PACKAGE,
field_transformations : [
{
when : {
type: TYPE_ENUM
}
set : {[scalapb.field] {type : 'String'}}
}
}
The next step will be to define a typemapper for all enums. Borrowing from Ivan's answer, this could be defined as follows:
implicit def enumMapper[E <: GeneratedEnum](implicit ec: GeneratedEnumCompanion[E]) =
TypeMapper[E, String](_.name)(ec.fromName(_).get)
If the above code is added to a package object in the same package as the generated code, or imported using the import option in ScalaPB, the typemapper will be found in implicit search.
You can't completely avoid defining TypeMapper for each enum type you have. But you could create a helper method to create TypeMapper instances.
For example
import scalapb.GeneratedEnum
import scalapb.GeneratedEnumCompanion
import scalapb.TypeMapper
def enumMapper[E <: GeneratedEnum: GeneratedEnumCompanion] = {
TypeMapper[E, String](_.name)(implicitly[GeneratedEnumCompanion[E]].fromName(_).get)
}
---UPDATE---
Following on #thesamet comment, if you add implicit to the method above and have it available in your implicit context, it will work.
This can be tested with following code that compiles
implicit def enumMapper...
val Enum1Mapper = implicitly[TypeMapper[E1]]

Scala 3 macro: generic type from class

I am writing a serialization library using Scala 3 macro programming.
I want to generate the serializer dynamicly. Because this is a library, so I do not know what class to serializer during compile. So I need a runtime compile feature.
Code:
object CodecMacro {
import scala.quoted.staging.*
given Compiler = Compiler.make(getClass.getClassLoader)
// function 1: entry point: a Class object
def buildSerializer(clazz: Class[_]): Serializer = {
given staging.Compiler = staging.Compiler.make(getClass.getClassLoader)
val fn = (qctx: Quotes) ?=> {
given q: Quotes = qctx
buildSerializerAdapter(clazz)
}
staging.run(fn)
}
// function 2: convert clazz to generic T
// My main question is here
private def buildSerializerAdapter(clazz: Class[_])(using quotes: Quotes): Expr[Serializer] = {
import quotes.reflect.*
val tpe: TypeRepr = TypeRepr.typeConstructorOf(clazz)
val t = tpe.asType
type T = t.Underlying
buildSerializerImpl[T] // error: Missing type parameters for T
}
// function 3: Using a generic T to generate a Serializer
private def buildSerializerImpl[T: Type](using quotes: Quotes): Expr[Serializer] = {
val t = summon[Type[T]]
'{
type T = t.Underlying
new Serializer[T] {
override def serialize(writer: Writer, value: T): Unit = {
// Implemetation, not important
writer.writeString("aaa")
}
}
}
Function 1 is the entry point, which needs a Class object.
Function 3 is the final implementation, which needs a generic type T.
Function 2 is to convert from Class object to generic type T and this is my main question.
My solution is
Class -> TypeRepr use: TypeRepr.typeConstructorOf(clazz)
TypeRepr -> Type use: TypeRepr.asType
Type -> type T use: Type.Underlying
I thought the type T under Type will solve my problem, but the compiler gives me an error:
"Missing type parameters for T"
In Function 3:
type T = t.Underlying
value: T
The generic type T is working fine.
Is there any way to convert Class object to generic type T?
Here is the way it should be done:
tpe.asType match
case '[t] =>
buildSerializerImpl[t]
This very strange invocation comes straight from the documentation of asType. It is necessary because asType returns a Type[?] where Type accepts any type kind, but here we want a concrete type kind. The match would fail if the type was of higher kind, such as a Type[List] (the List constructor takes type arguments).

Cast Anonymous (Any) object to class object in kotlin

Kotlin compiler is giving me error while running below :
fun main() {
val x = object {
val i = 1
val k = "s"
}
val y = x as Planet
if (y is Planet) {
println("Hello " + x.i)
}
}
data class Planet(
var i : Int,
var k : String
)
Error :
Exception in thread "main" java.lang.ClassCastException:
FileKt$main$x$1 cannot be cast to Planet at FileKt.main (File.kt:7)
at FileKt.main (File.kt:-1) at
sun.reflect.NativeMethodAccessorImpl.invoke0
(NativeMethodAccessorImpl.java:-2)
I am unable to understand why i am not able to cast Any object type to specific class object.
Isn't all Kotlin classes inherit from Any super class?
please let me know what i am doing wrong here.
Kotlin is a strongly statically typed language. Every variable and every expression has a type that is known at compile time.
In your example you are not specifying the type, but that does not mean it is unknown at compile time.
Kotlin uses type inference to determine its type. In your case Any.
val x: Any = object {
// ...
}
Any is the root of the Kotlin class hierarchy. Every Kotlin class has Any as a superclass.
This is the reason why you can not cast Any to Planet at runtime.
What you could do is using Kotlin safe-cast as? which returns null instead of an exception:
val planet: Planet? = x as? Planet
What you also can do, if you ever casted a Planet to Any, you can cast it back to Planet.
data class Planet(val name: String)
val pluto: Planet = Planet("Pluto")
val anyPlanet: Any = pluto
val planet: Planet = anyPlanet as Pluto
Thanks to Selvins comments for pointing me to right direction, the problem with my implementation is that i am trying to convert an object to type that is not Planet.
But the problem is that i needed to implement some way to screen the incoming object that is supposed to be of type Planet.
So below is the new implementation where i am checking for property of Planet against the anonymous object, if i get object with any fields other than what is present in Planet it will do nothing.
fun main() {
val x = object {
val i = 1
val k = "s"
}
val i = Planet::class.java.declaredFields.asIterable()
val j = x.javaClass.declaredFields.asIterable()
val b = i.zip(j).all { (f, a) -> f.name == a.name }
if (b){
x.let {
val p = Planet(i=it.i,k=it.k)
Log.d("TAG","$p")
}
}
}
data class Planet( val i: Int, val k: String)
May be not the best way, but feel free to comment.

Inheriting abstract types causing error saying that class is not an enclosing class

I am new to scala and am having trouble with inheriting from abstract type members. The code is the basis of a behaviour trees library I am building to get myself used to scala. I have simplified my code to something which best represents the problem:
trait Task {
type DataIn
type DataOut
def run(item: DataIn): (Boolean,Option[DataOut])
}
trait TaskContainer extends Task {
def task: Task
}
case class ResultInverter[I](override val task: Task{
type DataIn = ResultInverter.this.DataIn})
extends TaskContainer {
type DataIn = I
type DataOut = Nothing
override def run(item: DataIn): (Boolean,Option[DataOut])={
val taskOut = task(item)
if (taskOut._1 == true) ((false,None))
else (true,None)
}
}
object TaskTest extends App {
val isPositive = new Task {
type DataIn = Int
type DataOut = Nothing
override def run(item: DataIn): (Boolean,Option[DataOut])={
(item > 0, None)
}
}
println(ResultInverter[Int](isPositive(1)._1))
}
this gives the errors
error: ResultInverter is not an enclosing class
type DataIn = ResultInverter.this.DataIn})
^
error: Task{type DataIn = } does not take parameters
val taskOut = task(item)
^
error: stable identifier required, but .this found.
type DataIn = ResultInverter.this.DataIn})
^
error: Task{type DataIn = Int; type DataOut = Nothing} does not take parameters
val isNegative = ResultInverter[Int](isPositive(1)._1
I believe that error is coming from the line type DataIn = ResultInverter.this.DataIn. I have tried changing this to type DataIn = ResultInverter#DataIn but very little changed in terms of errors. I have programmed in java before so would have used type parameters instead of type members but I am pretty sure that type members are recommended.
Thanks for your help
You can't reference this in the signature of a constructor. At the moment a constructor is invoked there is no this yet. In your case you can just use I instead.
case class ResultInverter[I](task: Task{ type DataIn = I }) extends TaskContainer { ... }
The other errors are because you attempt to call the apply method (a(b) translates to a.apply(b)), but Task only has a run method.

Scala in depth - Existential types

I am currently reading Scala in depth and I struggle with a point about existential types.
Using those sources : https://github.com/jsuereth/scala-in-depth-source/blob/master/chapter6/existential-types/existential.scala
with openjdk 7 and scala 2.10.3
The following instructions gives me a error :
val x = new VariableStore[Int](12)
val d = new Dependencies {}
val t = x.observe(println)
d.addHandle(t)
<console>:14: error: method addHandle in trait Dependencies cannot be accessed in types.Dependencies
Access to protected method addHandle not permitted because
enclosing object $iw is not a subclass of
trait Dependencies in package types where target is defined
d.addHandle(t)
^
And I can't find out why and how I arrive to this error.
Edit 1 :
I added the following code from Kihyo's answer :
class MyDependencies extends Dependencies {
override def addHandle(handle: Ref) = super.addHandle(handle)
}
val x = new VariableStore[Int](12)
val d = new MyDependencies
val t = x.observe(println)
d.addHandle(t) //compiles
It make addHandle public instead of protected.
Now I have the following error message :
type mismatch; found : x.Handle (which expands to) x.HandleClass required: d.Ref (which
expands to) x.Handle forSome { val x: sid.types.obs.Observable }
HandleClass is a Handle and Ref is a Handle of any Observer (if I get it right) so the value t should be accepted as a correct type for the exception.
In the trait Dependencies, addHandle is defined like that:
protected def addHandle(handle : Ref) : Unit
protected means, only subclasses can access this method and thats why you get the error. (which basically tells you exactly that)
Your code could work when you create a subclass that makes addHandle public:
class MyDependencies extends Dependencies {
override def addHandle(handle: Ref) = super.addHandle(handle)
}
val x = new VariableStore[Int](12)
val d = new MyDependencies
val t = x.observe(println)
d.addHandle(t) //compiles
But I have no idea about that example and what you want to do with it.
#Edit1:
I get the same error as you, but I can't explain why. It worked for me when I extend App instead of having a main-method:
object TestObs extends App {
val x = new VariableStore[Int](12)
val d = new MyDependencies
val t = x.observe(println)
d.addHandle(t)
}
Maybe someone else has some insight on this.