Get all the classes that implements a trait in Scala using reflection - scala

I want to list out all the case classes which implements a particular trait. I am currently using Clapper ClassUtil for doing that. I am able to get the case classes that are directly implementing a trait. However, I am not able to get the other classes which are not directly implementing the trait. How can I get all classes which directly or indirectly implements a trait. ?
val finder = ClassFinder()
finder.getClasses().filter(_.isConcrete).filter(_.implements("com.myapp.MyTrait"))
Scala Version : 2.11
Clapper Class Util Version : 1.0.6
Is there any other way I can get these information? Can someone point me to the right direction?
I tried using scala.reflect but could not understand how to get the info.
EDIT:
Sample traits and usages:
trait BaseEntity
trait NamedEntity{ val name:String}
trait MasterDataEntity extends NamedEntity
case class Department(id:Long, override val name:String) extends MasterDataEntity
case class Employee(id:Long, name:String) extends BaseEntity
case class User(id:Long, override val name:String) extends NamedEntity
Now, if I give the trait as NamedEntity, I should be able to get both Department and User since they both are directly or indirectly implementing NamedEntity. With implements method, it will give only User. I also tried by using interfaces method, which will also provide the direct super classes only.

Looking at the source code, the problem seems to be that it doesn't follow the interfaces hierarchy. If you do that, you find all instances:
package foo
import java.io.File
import org.clapper.classutil.{ClassFinder, ClassInfo}
object Main extends App {
val jar = new File("target/scala-2.11/class_test_2.11-0.1.0.jar")
val finder = ClassFinder(jar :: Nil)
val classes = ClassFinder.classInfoMap(finder.getClasses().iterator)
val impl = find("foo.NamedEntity", classes)
impl.foreach(println)
def find(ancestor: String, classes: Map[String, ClassInfo]): List[ClassInfo] =
classes.get(ancestor).fold(List.empty[ClassInfo]) { ancestorInfo =>
val ancestorName = ancestorInfo.name
def compare(info: ClassInfo): Boolean =
info.name == ancestorName ||
(info.superClassName :: info.interfaces).exists {
n => classes.get(n).exists(compare)
}
val it = classes.valuesIterator
it.filter { info => info.isConcrete && compare(info) } .toList
}
}

ClassUtil now contains this functionality (v1.4.0, maybe also in earlier versions):
val finder = ClassFinder()
val impl = ClassFinder.concreteSubclasses("foo.NamedEntity", finder.getClasses())

Related

How to list annotations (custom java ones and others) on field members of Scala case class

So I'm trying to list fields with specific annotation in a Scala case class and I'm not able to get it working... Let's see come code right away
The case class (it's a simplified version of it, mine extends another class and is also nested in my test class where I use it for unit testing only):
case class Foo(#Unique var str: String) {}
The custom Java annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.PARAMETER})
public #interface Unique {}
And my class (simplified again) where I'm trying to do some stuffs with fields marked as unique
class SomeClass[T] (implicit typeTag: TypeTag[T]) {
val fields: Iterable[universe.TermSymbol] = typeOf(typeTag).members.collect { case s: TermSymbol => s }.
filter(s => s.isVal || s.isVar)
val list = fields.flatMap(f => f.annotations.find(_.tpe =:= TypeOf[Unique]).((f, _))).toList
}
But the val list in the last peace of code is always empty... fields has str listed in but without the annotation.
What am I missing?
The code listing the annotations is from the following answer:
How to list all fields with a custom annotation using Scala's reflection at runtime?
Seems the reference post is Scala 2.10 is old and is not compatible with the newest Scala version.
There is an example for how to get the specify annotation by type.
def listProperties[T: TypeTag]: List[universe.Annotation] = {
typeOf[T].typeSymbol.asClass
.asClass
.primaryConstructor
.typeSignature
.paramLists.flatten.flatMap(_.annotations)
}
val annotations = listProperties[Foo].filter(_.tree.tpe =:= typeOf[Unique])
println(annotations)
and there is way to get the annotation's field value:
case class Foo(#Unique(field = "bar") val str: String) {}
import scala.reflect.runtime.currentMirror
import scala.tools.reflect.ToolBox
val tb = currentMirror.mkToolBox()
val result = tb.eval(tb.untypecheck(head.tree)).asInstanceOf[Unique]
and need to call out your annotation class is implemented by using Java style, In Scala maybe you want to use StaticAnnotation for creating Annotation, like:
class Unique extends StaticAnnotation

How can I pass an instance to a ServiceInjector trait with scala?

I'm following the advice from com.googlegroups.google-guice http://markmail.org/message/ljnhl6rstverrxuj
Well, it's actually almost as referred to you in the link from the other answer:
http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di/
class MyClient {
#Inject val toBeInjected: AnotherClass = toBeInjected // !!
}
trait ServiceInjector {
ServiceInjector.inject( this )
}
object ServiceInjector {
private val injector = Guice.createInjector( Array[Module]( new YourModule ) )
def inject( obj: AnyRef ) = injector.injectMembers( obj )
}
Usage:
val client = new MyClient with ServiceInjector
or:
class InjectedMyClient extends MyClient with ServiceInjector
But I'm very new to Scala and trying to work out how I can use the following pattern for dependency injection, when the Guice Module itself needs references to instances passed in from elsewhere.
But since traits can't have constructors, and neither can the Companion Object it looks like I'm screwed?
package au.id.rleach.overmind.guice
import com.google.inject.{Provides, Guice, Binder, Module}
import org.slf4j.Logger
import org.spongepowered.api.service.ServiceManager
import org.spongepowered.api.world.TeleportHelper
import org.spongepowered.api.{GameRegistry, Game}
import org.spongepowered.api.plugin.PluginManager
import org.spongepowered.api.scoreboard.ScoreboardBuilder
import org.spongepowered.api.service.event.EventManager
class OModule(val game: Game, val logger: Logger, val pluginManager: PluginManager, val serviceManager: ServiceManager, val eventManager: EventManager, val gameRegistry: GameRegistry, val teleportHelper: TeleportHelper) extends Module {
override def configure(binder: Binder): Unit = {
binder.bind(classOf[Game]).toInstance(game)
binder.bind(classOf[Logger]).toInstance(logger)
binder.bind(classOf[PluginManager]).toInstance(pluginManager)
binder.bind(classOf[ServiceManager]).toInstance(serviceManager)
binder.bind(classOf[EventManager]).toInstance(eventManager)
binder.bind(classOf[GameRegistry]).toInstance(gameRegistry)
binder.bind(classOf[TeleportHelper]).toInstance(teleportHelper)
//bind(classOf[File]).annotatedWith(new ConfigDirAnnotation(true)).toInstance(Loader.instance.getConfigDir)
}
}
trait ServiceInjector {
ServiceInjector.inject(this)
}
object ServiceInjector {
private val injector = Guice.createInjector(
//####
new OModule()//compilation error.
//####
)
def inject(obj: AnyRef) = injector.injectMembers(obj)
}
I realize that the object is being initialized when it's first used, and that is after I have a copy of the instances to pass to OModule, but I can't seem to find a way to pass them in to the object.
Since I'm using Scala I am not a fan anymore of using DI frameworks since Scala has natively DI-like support already. This is called the Cake Pattern. There are plenty resources available on this, like this blogpost from Cake Solutions.
Both at ScalaDays 2014 and Devoxx 2014 Dick Wall also presented about a more lightweight DI solution which he called the Parfait Pattern. Both talks can be viewed on Parleys.com
If you really want to use a DI framework, Scaldi is a nice looking Scala framework utilising Scala features, but of course you can also keep on using Spring or Guice.
I'm not sure about this:
#Inject val toBeInjected: AnotherClass = toBeInjected
wouldn't work in my experience. It needs to be a var rather than val and the initial value null.
#Inject var toBeInjected: AnotherClass = null
I created a demo on GitHub which is the Play-Scala template with the index method changed as follows:
class Application extends Controller {
#Inject var ws: WSClient = null
def index = Action.async {
ws.url("http://google.com").get.map(r => Ok(r.body))
}
}
which worked well. That injected to a field, rather than as a constructor parameter. The same technique can be used with traits.

Is there anyway to create a new Scala object from a Java Class

I have a number of use cases for this, all around the idea of interop between existing Java libraries and new Scala Code. The use case I've selected is the easiest I think.
Use Case:
I working on providing a JUnit Runner for some scala tests (so that I can get my lovely red / green bar in Eclipse)
The runner needs to have a constructor with a java class as a parameter. So in Scala I can do the following:
class MyRunner(val clazz: Class[Any]) extends Runner {
def getDescription(): Description
def run(notifier: RunNotifier)
}
When I use either
#RunWith(MyRunner)
object MyTestObject
or
#RunWith(MyRunner)
class MyTestClass
then the runner is indeed instantiated correctly, and is passed a suitable class object
Unfortunately what i want to do now is to "get hold of" the object MyTestObject, or create a MyTestClass, which are both Scala entities. I would prefer to use Scala Reflection, but I also want to use the standard Junit jar.
What I have done
The following Stackover flow questions were educational, but not the same problem. There were the nearest questions I could find
How to create a TypeTag manually?
Any way to obtain a Java class from a Scala (2.10) type tag or symbol?
Using Scala reflection with Java reflection
The discussion on Environments, Universes and Mirrors in http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html was good, and the similar documents on other scala reflection also helped. Mostly through it is about the Scala reflection.
I browsed the Scaladocs, but my knowledge of Scala reflection wasn't enough (yet) to let me get what I wanted out of them.
Edit:
As asked here is the code of the class that is being created by reflection
#RunWith(classOf[MyRunner])
object Hello2 extends App {
println("starting")
val x= "xxx"
}
So the interesting thing is that the solution proposed below using the field called MODULE$ doesn't print anything and the value of x is null
This solution works fine if you want to use plan old java reflection. Not sure if you can use scala reflection given all you will have is a Class[_] to work with:
object ReflectTest {
import collection.JavaConversions._
def main(args: Array[String]) {
val fooObj = instantiate(MyTestObject.getClass())
println(fooObj.foo)
val fooClass = instantiate(classOf[MyTestClass])
println(fooClass.foo)
}
def instantiate(clazz:Class[_]):Foo = {
val rm = ru.runtimeMirror(clazz.getClassLoader())
val declaredFields = clazz.getDeclaredFields().toList
val obj = declaredFields.find(field => field.getName() == "MODULE$") match{
case Some(modField) => modField.get(clazz)
case None => clazz.newInstance()
}
obj.asInstanceOf[Foo]
}
}
trait Foo{
def foo:String
}
object MyTestObject extends Foo{
def foo = "bar"
}
class MyTestClass extends Foo{
def foo = "baz"
}

How to mix in traits with implicit vals of the same name but different types?

I have traits from two third party libraries that I'm trying to mix in to my own trait. They both define implicit vals named log.
However, they are of different types - one is an SLF4J Logger, the other is a Spray LoggingContext (which is really an Akka LoggingAdapter). In fact the second trait is from Spray, it's an HttpServer. (Not the most recent version you can find on Github which no longer has that val).
So, here's the code (library one renamed because it's proprietary, the Spray code snipped to show just relevant part):
object LibraryOneShim {
trait LibraryOne {
implicit val log: org.slf4j.Logger = ...
}
}
// https://github.com/spray/spray/blob/a996a5b6bdd830e613583fed86e87bf049fdb8c0/spray-routing/src/main/scala/spray/routing/HttpService.scala
trait HttpService extends Directives {
val log = LoggingContext.fromActorRefFactory // this is a LoggingContext/LoggingAdapter
}
trait MyTrait extends HttpService with LibraryOne {
val myRoute = ...
}
class MyActor extends Actor with MyTrait {
def receive = runRoute(myRoute)
}
This won't compile. The compiler complains:
error: overriding lazy value log in trait HttpService of type
java.lang.Object with spray.util.LoggingContext; lazy value log in
trait LibraryOne$class of type org.slf4j.Logger needs `override'
modifier trait DemoService extends HttpService with LibraryOne {
Is there any way I can mix in these two traits together?
As far as I can tell the only way is to create a CombinedLogger
class CombinedLogger(l1:Logger, l2:LoggingAdapter) extends Logger with LoggingAdapter {
// proxy methods to the correct logger
}
If both loggers were declared as def you could use it like this:
override def log = new CombinedLogger(super[LibraryOne].log, super[HttpService].log)
In this case it's tricky because they are defined as val which tell the Scala compiler they are a single value that will not change. And because of that it will not allow you to call super.log. So you would need to copy the logic of the overridden traits.
The other tricky part in this case is that you would need to proxy 50+ methods in the CombinedLogger.

case class copy 'method' with superclass

I want to do something like this:
sealed abstract class Base(val myparam:String)
case class Foo(override val myparam:String) extends Base(myparam)
case class Bar(override val myparam:String) extends Base(myparam)
def getIt( a:Base ) = a.copy(myparam="changed")
I can't, because in the context of getIt, I haven't told the compiler that every Base has a 'copy' method, but copy isn't really a method either so I don't think there's a trait or abstract method I can put in Base to make this work properly. Or, is there?
If I try to define Base as abstract class Base{ def copy(myparam:String):Base }, then case class Foo(myparam:String) extends Base results in class Foo needs to be abstract, since method copy in class Base of type (myparam: String)Base is not defined
Is there some other way to tell the compiler that all Base classes will be case classes in their implementation? Some trait that means "has the properties of a case class"?
I could make Base be a case class, but then I get compiler warnings saying that inheritance from case classes is deprecated?
I know I can also:
def getIt(f:Base)={
(f.getClass.getConstructors.head).newInstance("yeah").asInstanceOf[Base]
}
but... that seems very ugly.
Thoughts? Is my whole approach just "wrong" ?
UPDATE I changed the base class to contain the attribute, and made the case classes use the "override" keyword. This better reflects the actual problem and makes the problem more realistic in consideration of Edmondo1984's response.
This is old answer, before the question was changed.
Strongly typed programming languages prevent what you are trying to do. Let's see why.
The idea of a method with the following signature:
def getIt( a:Base ) : Unit
Is that the body of the method will be able to access a properties visible through Base class or interface, i.e. the properties and methods defined only on the Base class/interface or its parents. During code execution, each specific instance passed to the getIt method might have a different subclass but the compile type of a will always be Base
One can reason in this way:
Ok I have a class Base, I inherit it in two case classes and I add a
property with the same name, and then I try to access the property on
the instance of Base.
A simple example shows why this is unsafe:
sealed abstract class Base
case class Foo(myparam:String) extends Base
case class Bar(myparam:String) extends Base
case class Evil(myEvilParam:String) extends Base
def getIt( a:Base ) = a.copy(myparam="changed")
In the following case, if the compiler didn't throw an error at compile time, it means the code would try to access a property that does not exist at runtime. This is not possible in strictly typed programming languages: you have traded restrictions on the code you can write for a much stronger verification of your code by the compiler, knowing that this reduces dramatically the number of bugs your code can contain
This is the new answer. It is a little long because few points are needed before getting to the conclusion
Unluckily, you can't rely on the mechanism of case classes copy to implement what you propose. The way the copy method works is simply a copy constructor which you can implement yourself in a non-case class. Let's create a case class and disassemble it in the REPL:
scala> case class MyClass(name:String, surname:String, myJob:String)
defined class MyClass
scala> :javap MyClass
Compiled from "<console>"
public class MyClass extends java.lang.Object implements scala.ScalaObject,scala.Product,scala.Serializable{
public scala.collection.Iterator productIterator();
public scala.collection.Iterator productElements();
public java.lang.String name();
public java.lang.String surname();
public java.lang.String myJob();
public MyClass copy(java.lang.String, java.lang.String, java.lang.String);
public java.lang.String copy$default$3();
public java.lang.String copy$default$2();
public java.lang.String copy$default$1();
public int hashCode();
public java.lang.String toString();
public boolean equals(java.lang.Object);
public java.lang.String productPrefix();
public int productArity();
public java.lang.Object productElement(int);
public boolean canEqual(java.lang.Object);
public MyClass(java.lang.String, java.lang.String, java.lang.String);
}
In Scala, the copy method takes three parameter and can eventually use the one from the current instance for the one you haven't specified ( the Scala language provides among its features default values for parameters in method calls)
Let's go down in our analysis and take again the code as updated:
sealed abstract class Base(val myparam:String)
case class Foo(override val myparam:String) extends Base(myparam)
case class Bar(override val myparam:String) extends Base(myparam)
def getIt( a:Base ) = a.copy(myparam="changed")
Now in order to make this compile, we would need to use in the signature of getIt(a:MyType) a MyType that respect the following contract:
Anything that has a parameter myparam and maybe other parameters which
have default value
All these methods would be suitable:
def copy(myParam:String) = null
def copy(myParam:String, myParam2:String="hello") = null
def copy(myParam:String,myParam2:Option[Option[Option[Double]]]=None) = null
There is no way to express this contract in Scala, however there are advanced techniques that can be helpful.
The first observation that we can do is that there is a strict relation between case classes and tuples in Scala. In fact case classes are somehow tuples with additional behaviour and named properties.
The second observation is that, since the number of properties of your classes hierarchy is not guaranteed to be the same, the copy method signature is not guaranteed to be the same.
In practice, supposing AnyTuple[Int] describes any Tuple of any size where the first value is of type Int, we are looking to do something like that:
def copyTupleChangingFirstElement(myParam:AnyTuple[Int], newValue:Int) = myParam.copy(_1=newValue)
This would not be to difficult if all the elements were Int. A tuple with all element of the same type is a List, and we know how to replace the first element of a List. We would need to convert any TupleX to List, replace the first element, and convert the List back to TupleX. Yes we will need to write all the converters for all the values that X might assume. Annoying but not difficult.
In our case though, not all the elements are Int. We want to treat Tuple where the elements are of different type as if they were all the same if the first element is an Int. This is called
"Abstracting over arity"
i.e. treating tuples of different size in a generic way, independently of their size. To do it, we need to convert them into a special list which supports heterogenous types, named HList
Conclusion
Case classes inheritance is deprecated for very good reason, as you can find out from multiple posts in the mailing list: http://www.scala-lang.org/node/3289
You have two strategies to deal with your problem:
If you have a limited number of fields you require to change, use an approach such as the one suggested by #Ron, which is having a copy method. If you want to do it without losing type information, I would go for generifying the base class
sealed abstract class Base[T](val param:String){
def copy(param:String):T
}
class Foo(param:String) extends Base[Foo](param){
def copy(param: String) = new Foo(param)
}
def getIt[T](a:Base[T]) : T = a.copy("hello")
scala> new Foo("Pippo")
res0: Foo = Foo#4ab8fba5
scala> getIt(res0)
res1: Foo = Foo#5b927504
scala> res1.param
res2: String = hello
If you really want to abstract over arity, a solution is to use a library developed by Miles Sabin called Shapeless. There is a question here which has been asked after a discussion : Are HLists nothing more than a convoluted way of writing tuples? but I tell you this is going to give you some headache
If the two case classes would diverge over time so that they have different fields, then the shared copy approach would cease to work.
It is better to define an abstract def withMyParam(newParam: X): Base. Even better, you can introduce an abstract type to retain the case class type upon return:
scala> trait T {
| type Sub <: T
| def myParam: String
| def withMyParam(newParam: String): Sub
| }
defined trait T
scala> case class Foo(myParam: String) extends T {
| type Sub = Foo
| override def withMyParam(newParam: String) = this.copy(myParam = newParam)
| }
defined class Foo
scala>
scala> case class Bar(myParam: String) extends T {
| type Sub = Bar
| override def withMyParam(newParam: String) = this.copy(myParam = newParam)
| }
defined class Bar
scala> Bar("hello").withMyParam("dolly")
res0: Bar = Bar(dolly)
TL;DR: I managed to declare the copy method on Base while still letting the compiler auto generate its implementations in the derived case classes. This involves a little trick (and actually I'd myself just redesign the type hierarchy) but at least it goes to show that you can indeed make it work without writing boiler plate code in any of the derived case classes.
First, and as already mentioned by ron and Edmondo1984, you'll get into troubles if your case classes have different fields.
I'll strictly stick to your example though, and assume that all your case classes have the same fields (looking at your github link, this seems to be the case of your actual code too).
Given that all your case classes have the same fields, the auto-generated copy methods will have the same signature which is a good start. It seems reasonable then to just add the common definition in Base, as you did:
abstract class Base{ def copy(myparam: String):Base }
The problem is now that scala won't generate the copy methods, because there is already one in the base class.
It turns out that there is another way to statically ensure that Base has the right copy method, and it is through structural typing and self-type annotation:
type Copyable = { def copy(myParam: String): Base }
sealed abstract class Base(val myParam: String) { this : Copyable => }
And unlike in our earlier attempt, this will not prevent scala to auto-generate the copy methods.
There is one last problem: the self-type annotation makes sure that sub-classes of Base have a copy method, but it does not make it publicly availabe on Base:
val foo: Base = Foo("hello")
foo.copy()
scala> error: value copy is not a member of Base
To work around this we can add an implicit conversion from Base to Copyable. A simple cast will do, as a Base is guaranteed to be a Copyable:
implicit def toCopyable( base: Base ): Base with Copyable = base.asInstanceOf[Base with Copyable]
Wrapping up, this gives us:
object Base {
type Copyable = { def copy(myParam: String): Base }
implicit def toCopyable( base: Base ): Base with Copyable = base.asInstanceOf[Base with Copyable]
}
sealed abstract class Base(val myParam: String) { this : Base. Copyable => }
case class Foo(override val myParam: String) extends Base( myParam )
case class Bar(override val myParam: String) extends Base( myParam )
def getIt( a:Base ) = a.copy(myParam="changed")
Bonus effect: if we try to define a case class with a different signature, we get a compile error:
case class Baz(override val myParam: String, truc: Int) extends Base( myParam )
scala> error: illegal inheritance; self-type Baz does not conform to Base's selftype Base with Base.Copyable
To finish, one warning: you should probably just revise your design to avoid having to resort to the above trick.
In your case, ron's suggestion to use a single case class with an additional etype field seems more than reasonable.
I think this is what extension methods are for. Take your pick of implementation strategies for the copy method itself.
I like here that the problem is solved in one place.
It's interesting to ask why there is no trait for caseness: it wouldn't say much about how to invoke copy, except that it can always be invoked without args, copy().
sealed trait Base { def p1: String }
case class Foo(val p1: String) extends Base
case class Bar(val p1: String, p2: String) extends Base
case class Rab(val p2: String, p1: String) extends Base
case class Baz(val p1: String)(val p3: String = p1.reverse) extends Base
object CopyCase extends App {
implicit class Copy(val b: Base) extends AnyVal {
def copy(p1: String): Base = b match {
case foo: Foo => foo.copy(p1 = p1)
case bar: Bar => bar.copy(p1 = p1)
case rab: Rab => rab.copy(p1 = p1)
case baz: Baz => baz.copy(p1 = p1)(p1.reverse)
}
//def copy(p1: String): Base = reflect invoke
//def copy(p1: String): Base = macro xcopy
}
val f = Foo("param1")
val g = f.copy(p1="param2") // normal
val h: Base = Bar("A", "B")
val j = h.copy("basic") // enhanced
println(List(f,g,h,j) mkString ", ")
val bs = List(Foo("param1"), Bar("A","B"), Rab("A","B"), Baz("param3")())
val vs = bs map (b => b copy (p1 = b.p1 * 2))
println(vs)
}
Just for fun, reflective copy:
// finger exercise in the api
def copy(p1: String): Base = {
import scala.reflect.runtime.{ currentMirror => cm }
import scala.reflect.runtime.universe._
val im = cm.reflect(b)
val ts = im.symbol.typeSignature
val copySym = ts.member(newTermName("copy")).asMethod
def element(p: Symbol): Any = (im reflectMethod ts.member(p.name).asMethod)()
val args = for (ps <- copySym.params; p <- ps) yield {
if (p.name.toString == "p1") p1 else element(p)
}
(im reflectMethod copySym)(args: _*).asInstanceOf[Base]
}
This works fine for me:
sealed abstract class Base { def copy(myparam: String): Base }
case class Foo(myparam:String) extends Base {
override def copy(x: String = myparam) = Foo(x)
}
def copyBase(x: Base) = x.copy("changed")
copyBase(Foo("abc")) //Foo(changed)
There is a very comprehensive explanation of how to do this using shapeless at http://www.cakesolutions.net/teamblogs/copying-sealed-trait-instances-a-journey-through-generic-programming-and-shapeless ; in case the link breaks, the approach uses the copySyntax utilities from shapeless, which should be sufficient to find more details.
Its an old problem, with an old solution,
https://code.google.com/p/scala-scales/wiki/VirtualConstructorPreSIP
made before the case class copy method existed.
So in reference to this problem each case class MUST be a leaf node anyway, so define the copy and a MyType / thisType plus the newThis function and you are set, each case class fixes the type. If you want to widen the tree/newThis function and use default parameters you'll have to change the name.
as an aside - I've been waiting for compiler plugin magic to improve before implementing this but type macros may be the magic juice. Search in the lists for Kevin's AutoProxy for a more detailed explanation of why my code never went anywhere