Ein kleiner Mapper
Objekte zu Maps und zurück, gebaut auf AnnotationIntrospector. Dieselbe Form wie json-mapper, ohne JSON: ein praktischer erster Schritt, wenn du eigenen Framework-Code schreibst.
Modell
Mit einer Annotation zustimmen
Die Klasse markiert, was der Mapper anfassen darf. Alles andere bleibt ihr vorbehalten.
java
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface Exposed {}
scala
class Account {
@(Exposed @field) var owner: String = null
@(Exposed @field) var balance: java.math.BigDecimal = null
var audit: String = "not mapped"
}
Mapper
Zwei Richtungen, ein Modell
toMap liest jede freigegebene Property. fromMap erzeugt eine Instanz über den parameterlosen Konstruktor und schreibt jede schreibbare Property, die die Map enthält.
scala
import com.anjunar.scala.universe.TypeResolver
import com.anjunar.scala.universe.introspector.AnnotationIntrospector
object MiniMapper {
def toMap(value: AnyRef): Map[String, Any] =
val model = AnnotationIntrospector.create(TypeResolver.resolve(value.getClass), classOf[Exposed])
model.properties.map(property => property.name -> property.get(value)).toMap
def fromMap[T](clazz: Class[T], values: Map[String, Any]): T =
val resolved = TypeResolver.resolve(clazz)
val instance = resolved.findConstructor().newInstance().asInstanceOf[AnyRef]
AnnotationIntrospector.create(resolved, classOf[Exposed]).properties
.filter(_.isWriteable)
.foreach(property => values.get(property.name).foreach(property.set(instance, _)))
instance.asInstanceOf[T]
}
scala
val account = MiniMapper.fromMap(classOf[Account], Map("owner" -> "Ada", "balance" -> BigDecimal(12).bigDecimal))
println(MiniMapper.toMap(account))
Ausgabe
Map(owner -> Ada, balance -> 12)
Nächste Schritte
Wo ein echter Mapper weitergeht
Das Gerüst ist in json-mapper dasselbe; der Rest macht es zu Produktionscode.
Was json-mapper ergänzt
Typumwandlung je propertyType, Collections über typeArguments eingeschlossen.
Verschachtelte Objekte, an Ort und Stelle übernommen statt neu angelegt.
Ein Schema pro Klasse, gefunden über companionInstance, mit Sichtbarkeitsregeln.
Validierung vor jedem Schreiben, mit Pfaden für jeden Verstoß.
Modelle werden zwischengespeichert
AnnotationIntrospector.create hält ein Modell pro Klasse und Annotation; ein Aufruf pro Anfrage kostet einen Map-Zugriff. Wie der Typ-Cache ist diese Map nicht synchronisiert; fülle sie in einem Server beim Start.