2016-05-19 14 views
0

Ich bin auf der Suche nach einer generischen Möglichkeit, Paare von Fallklassen mit implicits zu konvertieren. Um dies zu konkretisieren, schreibe ich eine neue Konfigurationsbibliothek, die Abwärtskompatibilität mit einer vorhandenen Konfigurationsbibliothek aufrechterhalten muss. Um diesen Übergang so schmerzfrei wie möglich zu gestalten, hoffe ich, implits die neuen Fallklassen bei Bedarf auf ihre älteren Gegenstücke umstellen zu können. Im folgenden Beispiel befinden sich die Klassen 1 in der alten Bibliothek und die Klassen 2 stammen aus der neuen Bibliothek. Ich verwende apply auf den Companion-Objekten, um die tatsächlichen Daten aus der Config-Instanz zu extrahieren (mit der config-Bibliothek von TypeSafe).Scala: Generische Lösung, um Paare von Fallklassen implizit zu konvertieren

package older { 
    case class A1(a: String) 
    case class B1(b: Int) 
} 

package newer { 
    case class A2(a: String) 
    case class B2(b: Int) 

    object A2 { 
    def apply(cfg: Config): A2 = A2(a = cfg.getString("a")) 
    def toOlder(a2: A2) = older.A1(a = a2.a) 
    } 

    object B2 { 
    def apply(cfg: Config): B2 = B2(b = cfg.getInt("b")) 
    def toOlder(b2: B2) = older.B1(b = b2.b) 
    } 
} 

Idealerweise müsste ich nicht eine implizite Funktion zu schreiben, jeder der Fallklassen zu konvertieren (A1 ->A2, B1 ->B2, etc), aber eine einzige allgemeine implizite nutzen könnten alle zu handhaben Sie. Das Ziel ist, in der Lage sein, eine Instanz von A2 für die a1 Methode, indem Sie einfach unten zu verwenden, um die impliziten Import:

trait Foo { 
    def a1: older.A1 
} 

Ich habe jetzt meinen Kopf gegen die Wand für ein paar Stunden wurde hämmern und kann nicht kommen mit der Lösung.

Vielen Dank im Voraus.

Antwort

0

Natürlich nachdem ich von dem Problem, für ein paar Stunden ging weg kam ich mit der Lösung auf. Peinlicherweise ist es auch ziemlich einfach.

package older { 
    case class A1(a: String) 
    case class B1(b: Int) 
} 

package newer { 

    sealed trait Convertable[A <: AnyRef, B <: AnyRef] { 
     implicit val formats = DefaultFormats 

     implicit def convert(new: A)(implicit mB: Manifest[B]): B = { 
      read[B](write(new)) 
     } 
    } 

    case class A2(a: String) 
    case class B2(b: Int) 

    object A2 extends Convertable[A2, older.A1] { 
     def apply(cfg: Config): A2 = A2(a = cfg.getString("a")) 
    } 

    object B2 extends Convertabe[B2, older.B1] { 
     def apply(cfg: Config): B2 = B2(b = cfg.getInt("b")) 
    } 
} 

Beachten Sie auch, dass ich Aufzüge JSON Fähigkeit Fall Klassen zu JSON zu transformieren und zurück, um die tatsächlichen Instanziierung auszuführen. Scheint einfacher als mit Reflexion zu tun.

Vielen Dank für Ihre Hilfe!

1

Löst es Ihr Problem, oder habe ich etwas falsch verstanden?

implicit final def aToOlder(self: A2): A1 = A1(a = self.a) 
implicit final def bToOlder(self: B2): B1 = B1(b = self.b) 

Verbrauch:

val old: A1 = A1("John") 
val oldFromNew: A1 = A2("Doe") // This will be implicitly converted from the `A2` instance to the `A1` instance 
+0

Das wird funktionieren, aber ich hoffe zu vermeiden, eine implizite für jede Fallklasse zu schreiben. Danke für die Antwort! – richid