After running proguard, when i check if methods are available on the obfuscated jar in a new project depending on this last. Desired classes are there but i can't have access to companion object.
Library side
trait KeepOpen
trait KeepOpenObj
trait MyTrait extends KeepOpen {
def a: Int
}
object MyTrait extends KeepOpenObj {
def apply(arg: Int): MyTrait = new MyTrait { val a = 1 }
}
Depending project test.
import aaa.MyTrait
val arg = 1
def myTraitImpl: MyTrait = ??? // Type is well infered
def myTraitImpl2: MyTrait = MyTrait(arg) // MyTrait companion object is not detected preventing apply method usage
// But this works
def myTraitImpl3: MyTrait = (new MyTrait$)(arg) // Works
Here are my keep options for classes :
"-keep !final class * extends aaa.KeepOpen",
"-keep !final class * extends aaa.KeepOpen {*;}",
"-keep class * implements aaa.KeepOpenObj",
"-keep class * implements aaa.KeepOpenObj {*;}",
trait of the library inherit from KeepOpen and object including companion one extends KeepOpenObj.
Exploring the jar non obfuscate and obfuscate, they both show two file MyTrait and MyTrait$ with expecting methods but its impossible to use companion object in the obfuscated case.
Moreover non companion object like those with main seems to work without any problem.
Update
I success to make infer companion object type and its associate methods adding following options :
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
But unfortunately i fall on the following error when compiling.
val myTrait = MyTrait(arg) // error : class aaa.MyTrait is not a value
How can i have access to the companion object in the same way that with non obfuscate jar ?
Related
Given a code which takes a type, takes it's known direct subclasses, filters the ones that are case classes and then takes the companion of that case class:
def firstSubclassWithCompanion[T: TypeTag]: String = {
val superclass = implicitly[TypeTag[T]].tpe.typeSymbol.asClass
val caseClass = superclass.knownDirectSubclasses.map(_.asClass).filter(_.isCaseClass).head
s"case class $caseClass has companion ${caseClass.companion}"
}
With a simple example
sealed trait With
case class WithCase() extends With
It gives the expected return
> firstSubclassWithCompanion[With]
"class WithCase has companion object WithCase"
As With trait has a WithCase subclass, which is case class that has a companion object (defined by compiler).
However, given the following example, where the subclass is defined in the companion object of the inheriting trait:
sealed trait Without
object Without {
case class WithoutCase() extends Without
}
It doesn't return the companion object
> firstSubclassWithCompanion[Without]
"class WithoutCase has companion <none>"
It works fine if it's defined in other object.
Bugs should be reported at https://github.com/scala/bug/issues
A workaround is to use caseClass.owner.typeSignature.decl(caseClass.name) instead of caseClass.companion.
Another workaround is to translate this runtime-reflection code into a macro (compile-time reflection). Since all the classes here are defined at compile time it makes sense to use a macro.
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def firstSubclassWithCompanion[T]: String = macro firstSubclassWithCompanionImpl[T]
def firstSubclassWithCompanionImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
val superclass = weakTypeOf[T].typeSymbol.asClass
val caseClass = superclass.knownDirectSubclasses.map(_.asClass).filter(_.isCaseClass).head
val res = s"case class $caseClass has companion ${caseClass.companion}"
q"$res"
}
I am implementing an extension of ml.Transformer in Spark; but this question is Scala specific. Here is an example object (part of a Class/Object pair):
abstract class UDFTransformer(func: UserDefinedFunction,
inputFieldNames: Seq[String],
outputFieldName: String) extends Transformer with MLWritable with Serializable {
... definitions here ...
}
object UDFTransformer extends MLReadable[UDFTransformer] {
// Since there are no parameters associted with the UDF, there is nothing to save!
class Writer(instance: UDFTransformer) extends MLWriter {
override protected def saveImpl(path: String): Unit = {}
}
abstract protected class Reader extends MLReader[UDFTransformer]
override def read: MLReader[UDFTransformer] = new Reader
override def load(path: String): UDFTransformer = super.load(path)
}
The new Reader does not compile because the class is abstract and cannot be instantiated. But; any child class will have to define it; along with its necessary members. I cannot just make read abstract as well, this gives me a warning Only classes can have declared but undefined methods.
The fundamental problem is that each child class of my UDFTransformer is going to wrap a specific UDF. Therefore, the reader needs to be able to generate a specific UDF object; this can't be declared in the superclass. But this 'factory' belongs in the companion object, not in the abstract class itself.
How can I go about building a companion object for an abstract class that can leave the definition of read undefined?
The normal way to do it is by creating an abstract class or trait for the companion objects. Something like
abstract class UDFTransformerCompanion[T <: UDFTransformer] extends MLReadable[T] {
abstract def read: MLReader[T]
override def load(path: String): T = super.load(path)
}
class SomeTransformer extends UDFTransformer { ... }
object SomeTransformer extends UDFTransformerCompanion[SomeTransformer] {
override def read: MLReader[SomeTransformer] = ...
}
Not sure why you have the load = super.load override, and it doesn't look like you can have a companion object for the UDFTransformer itself, at least not one extending this abstract class.
See GenericTraversableTemplate for a standard library example.
Say I have the following two typeclasses:
object Foo {
sealed trait FooClass[A]
implicit object FooString extends FooClass[String]
implicit object FooInt extends FooClass[Int]
}
object Bar {
trait BarClass[A] //leave this one unsealed as we're attempting to prove that Foo is a subset of Bar, not the other way around.
implicit object BarString extends BarClass[String]
implicit object BarInt extends BarClass[Int]
implicit object BarDouble extends BarClass[Double]
}
is it possible to provide a hint to the compiler that Foo is a subset of Bar somehow, such that the following would compile, without a change to the type signatures of either method?
class Outer(callee : Inner) {
import Foo._
def call[A : FooClass](a) : Unit = callee.call(a);
}
class Inner
import Bar._
def call[B : BarClass](b) : Unit = ();
}
val test = new Outer(new Inner)
test.call(123)
test.call("Hello World")
My main objective is to allow the Outer class to be entirely unaware of the existence of the BarClass typeclass - using the Inner class to abstract over it entirely. Is this possible? For those who are interested, there's some context over in this git repository - the commit descriptions have some more detailed exposition of the problem I'm trying to solve).
I am trying to use the typeclass pattern in Scala to mark all the valid API serializable types, so that we can have compile-time safety around what we serialize. Our underlying library accepts an AnyRef which can lead to weird errors when not explicitly declaring the type before serializing it.
We allow sending out a public model, an iterable of public models, an option of public model, or a unit.
trait PublicModel
case class UserModel(name: String) extends PublicModel
sealed class SafeForPublic[-T]
implicit object PublicModelOk extends SafeForPublic[PublicModel]
implicit object IterablePublicModelOk extends SafeForPublic[Iterable[PublicModel]]
implicit object OptionPublicModelOk extends SafeForPublic[Option[PublicModel]]
implicit object UnitOk extends SafeForPublic[Unit]
This method works well for everything except methods where the parameter type is an option. This is because None is an Option[Nothing], so T = Nothing which will tell the compiler to look up an implicit object of type SafeForPublic[Nothing] and it will find both SafeForPublic[PublicModel] as well as SafeForPublic[Iterable[PublicModel]]
def boxed[T : SafeForPublic](t: Option[T]) = println("wooohoo!")
boxed(Some(None)) // works
boxed(Some(1)) // doesn't compile. Int is not a valid serializable model.
boxed(Some({})) // works
boxed(Some(UserModel("ok"))) // works
boxed(Some(Seq(UserModel("ok")))) // works
boxed(None) // doesn't compile, duplicate implicits ><
Any idea how I can trick the compiler to not find duplicate implicits for Nothing. I saw Miles Sabin had a trick using:
sealed trait NotNothing[A]{
type B
}
object NotNothing {
implicit val nothing = new NotNothing[Nothing]{ type B = Any }
implicit def notNothing[A] = new NotNothing[A]{ type B = A }
}
But I couldn't figure out how to use it. Halp?
Ok, thanks to some help from the Scala IRC channel, I figured out that LowPriority implicits was created to solve this issue.
I used this to fix it:
sealed class SafeForPublic[-T]
trait LowPriorityImplicits {
implicit object PublicModelOk extends SafeForPublic[PublicModel]
implicit object IterablePublicModelOk extends SafeForPublic[Iterable[PublicModel]]
implicit object OptionPublicModelOk extends SafeForPublic[Option[PublicModel]]
implicit object UnitOk extends SafeForPublic[Unit]
}
object Implicits extends LowPriorityImplicits {
implicit object NothingOk extends SafeForPublic[Nothing]
}
import Implicits._
def boxed[T : SafeForPublic](t: Option[T]) = println("woohoo!")
boxed(None) // compiles! \o/
Given a trait MyTrait:
trait MyTrait {
def doSomething = println("boo")
}
it can be mixed into a class with extends or with:
class MyClass extends MyTrait
It can also be mixed upon instantiating a new instance:
var o = new MyOtherClass with MyTrait
o.doSomething
But...can the trait (or any other if that makes a difference) be added to an existing instance?
I'm loading objects using JPA in Java and I'd like to add some functionality to them using traits. Is it possible at all?
I'd like to be able to mix in a trait as follows:
var o = DBHelper.loadMyEntityFromDB(primaryKey);
o = o with MyTrait //adding trait here, rather than during construction
o.doSomething
I have a idea for this usage:
//if I had a class like this
final class Test {
def f = println("foo")
}
trait MyTrait {
def doSomething = {
println("boo")
}
}
object MyTrait {
implicit def innerObj(o:MixTest) = o.obj
def ::(o:Test) = new MixTest(o)
final class MixTest private[MyTrait](val obj:Test) extends MyTrait
}
you can use this trait as below:
import MyTrait._
val a = new Test
val b = a :: MyTrait
b.doSomething
b.f
for your example code:
val o = DBHelper.loadMyEntityFromDB(primaryKey) :: MyTrait
o.doSomething
I hope this can help you.
UPDATED
object AnyTrait {
implicit def innerObj[T](o: MixTest[T]):T = o.obj
def ::[T](o: T) = new MixTest(o)
final class MixTest[T] private[AnyTrait](val obj: T) extends MyTrait
}
but this pattern has some restrict, you can't use some implicit helper method that defined already.
val a = new Test
a.f
val b = a :: AnyTrait
b.f1
b.f
val c = "say hello to %s" :: AnyTrait
println(c.intern) // you can invoke String's method
println(c.format("MyTrait")) //WRONG. you can't invoke StringLike's method, though there defined a implicit method in Predef can transform String to StringLike, but implicit restrict one level transform, you can't transform MixTest to String then to StringLike.
c.f1
val d = 1 :: AnyTrait
println(d.toLong)
d.toHexString // WRONG, the same as above
d.f1
An existing runtime object in the JVM has a certain size on the heap. Adding a trait to it would mean altering its size on the heap, and changing its signature.
So the only way to go would be to do some kind of transformation at compile time.
Mixin composition in Scala occurs at compile time. What compiler could potentially do is create a wrapper B around an existing object A with the same type that simply forwards all calls to the existing object A, and then mix in a trait T to B. This, however, is not implemented. It is questionable when this would be possible, since the object A could be an instance of a final class, which cannot be extended.
In summary, mixin composition is not possible on existing object instances.
UPDATED:
Related to the smart solution proposed by Googol Shan, and generalizing it to work with any trait, this is as far as I got. The idea is to extract the common mixin functionality in the DynamicMixinCompanion trait. The client should then create a companion object extending DynamicMixinCompanion for each trait he wants to have the dynamic mixin functionality for. This companion object requires defining the anonymous trait object gets created (::).
trait DynamicMixinCompanion[TT] {
implicit def baseObject[OT](o: Mixin[OT]): OT = o.obj
def ::[OT](o: OT): Mixin[OT] with TT
class Mixin[OT] protected[DynamicMixinCompanion](val obj: OT)
}
trait OtherTrait {
def traitOperation = println("any trait")
}
object OtherTrait extends DynamicMixinCompanion[OtherTrait] {
def ::[T](o: T) = new Mixin(o) with OtherTrait
}
object Main {
def main(args: Array[String]) {
val a = "some string"
val m = a :: OtherTrait
m.traitOperation
println(m.length)
}
}
I usually used a implicit to mix in a new method to an existing object.
See, if I have some code as below:
final class Test {
def f = "Just a Test"
...some other method
}
trait MyTrait {
def doSomething = {
println("boo")
}
}
object HelperObject {
implicit def innerObj(o:MixTest) = o.obj
def mixWith(o:Test) = new MixTest(o)
final class MixTest private[HelperObject](obj:Test) extends MyTrait
}
and then you can use MyTrait method with an already existing object Test.
val a = new Test
import HelperObject._
val b = HelperObject.mixWith(a)
println(b.f)
b.doSomething
in your example, you can use like this:
import HelperObject._
val o = mixWith(DBHelper.loadMyEntityFromDB(primaryKey));
o.doSomething
I am thinking out a prefect syntax to define this HelperObject:
trait MyTrait {
..some method
}
object MyTrait {
implicit def innerObj(o:MixTest) = o.obj
def ::(o:Test) = new MixTest(o)
final class MixTest private[MyTrait](obj:Test) extends MyTrait
}
//then you can use it
val a = new Test
val b = a :: MyTrait
b.doSomething
b.f
// for your example
val o = DBHelper.loadMyEntityFromDB(primaryKey) :: MyTrait
o.doSomething
What about an implicit class? It seems easier to me compared to the way in the other answers with a final inner class and a "mixin"-function.
trait MyTrait {
def traitFunction = println("trait function executed")
}
class MyClass {
/**
* This inner class must be in scope wherever an instance of MyClass
* should be used as an instance of MyTrait. Depending on where you place
* and use the implicit class you must import it into scope with
* "import mypackacke.MyImplictClassLocation" or
* "import mypackage.MyImplicitClassLocation._" or no import at all if
* the implicit class is already in scope.
*
* Depending on the visibility and location of use this implicit class an
* be placed inside the trait to mixin, inside the instances class,
* inside the instances class' companion object or somewhere where you
* use or call the class' instance with as the trait. Probably the
* implicit class can even reside inside a package object. It also can be
* declared private to reduce visibility. It all depends on the structure
* of your API.
*/
implicit class MyImplicitClass(instance: MyClass) extends MyTrait
/**
* Usage
*/
new MyClass().traitFunction
}
Why not use Scala's extend my library pattern?
https://alvinalexander.com/scala/scala-2.10-implicit-class-example
I'm not sure what the return value is of:
var o = DBHelper.loadMyEntityFromDB(primaryKey);
but let us say, it is DBEntity for our example. You can take the class DBEntity and convert it to a class that extends your trait, MyTrait.
Something like:
trait MyTrait {
def doSomething = {
println("boo")
}
}
class MyClass() extends MyTrait
// Have an implicit conversion to MyClass
implicit def dbEntityToMyClass(in: DBEntity): MyClass =
new MyClass()
I believe you could also simplify this by just using an implicit class.
implicit class ConvertDBEntity(in: DBEntity) extends MyTrait
I particularly dislike the accepted answer here, b/c it overloads the :: operator to mix-in a trait.
In Scala, the :: operator is used for sequences, i.e.:
val x = 1 :: 2 :: 3 :: Nil
Using it as a means of inheritance feels, IMHO, a little awkward.