Mein Scalan und Liften, Please find below a very simplistic view of transform a POJO to an XML container. At it's heart is the recognition that a POJO is an in-memory representation of a relation. i would like to generalize this code to include other container types, e.g. JSON. i started down the path of abstracting the type for the container, but realized the container ctor might -- as in the case of XML -- have a reliance on some outer context/scope. (In the case of XML the scala Elem ctor requires arguments like a namebinding scope and a prefix and a bunch of other things.) So, the abstraction along the lines of requiring that the container have a prototypical object that supported an apply method became a prohibitively complex design pattern. My question then, is what's a simpler design pattern that will
- keep the core design principle that what we really have here is a monad (more accurately a monad transformer -- the POJO itself is really a monad and the code to change the shape is a means of transforming one kind of comprehension/monad to another) - allow for a wider range of possible target container types (XML, JSON, kinda-separated-lists[1], dump format for MySQL,...) Best wishes, --greg [1] Not to be confused with comma-separated-lists that are almost never found in the wild, kinda-separated-lists occur everywhere where programs and other creatures might dump data and forget a comma or two or... package com.sap.dspace.model.othello; import scala.xml._ trait XMLRenderer { def recurse() : Boolean def failOnUnknownType() : Boolean def inView( field : java.lang.reflect.Field, pojo : {def getClass() : java.lang.Class[_]} ) : Boolean = { // a possible strategy is to create a little DSL for views and // process those here true } def isGroundValueType( value : {def getClass() : java.lang.Class[_]} ) : Boolean = { ((value.isInstanceOf[Boolean]) || (value.isInstanceOf[Integer]) || (value.isInstanceOf[Float]) || (value.isInstanceOf[String]) // put more ground types here ) } def groundValue2Container( value : {def getClass() : java.lang.Class[_]} ) : Node = { Text( value.toString ) } def unmatchedValue2Container( vUnmatched : {def getClass() : java.lang.Class[_]}, field : java.lang.reflect.Field, pojo : {def getClass() : java.lang.Class[_]} ) : Node = { if (! failOnUnknownType() ) <unmatchedType> <theType> {vUnmatched.getClass.toString} </theType> <theValue> {vUnmatched.toString} </theValue> </unmatchedType> else throw new Exception( ( "unmatched type" + vUnmatched.getClass.toString + "when attempting render the " + field.getName + "field of " + pojo ) ) } def value2Container( value : {def getClass() : java.lang.Class[_]}, field : java.lang.reflect.Field, pojo : {def getClass() : java.lang.Class[_]} ) : Node = { value match { case null => Text( "null" ) case vUnmatched => if ( isGroundValueType( vUnmatched ) ) groundValue2Container( vUnmatched ) else if ((value.isInstanceOf[java.io.Serializable]) && (recurse())) pojo2Container( value.asInstanceOf[{def getClass() : java.lang.Class[_]}] ) else unmatchedValue2Container( vUnmatched, field, pojo ) } } def field2Container( field : java.lang.reflect.Field, pojo : {def getClass() : java.lang.Class[_]} ) : Node = { // reflectively break java access control mechanisms val accessible = field.isAccessible; field.setAccessible( true ); val fldValXML : Node = value2Container( field.get( pojo ),field, pojo ) // put java access mechanisms back in place field.setAccessible( accessible ); Elem( null, field.getName, null, TopScope, fldValXML ) } // This is the basic monadic/monad transformer view of the pojo // rendering process. It shouldn't be surprising that this would // have this form: if you stop to think about it a pojo is a relation. def pojo2Container( pojo : {def getClass() : java.lang.Class[_]} ) : Node = { val tag = pojo.getClass.getSimpleName; val progeny = for (field <- pojo.getClass.getDeclaredFields if inView( field, pojo )) yield field2Container( field, pojo); Elem( null, tag, null, TopScope, (progeny : _*)) } } case class POJO2XMLRenderer( doRecurse : Boolean, doFastFail : Boolean ) extends XMLRenderer { override def recurse() = doRecurse override def failOnUnknownType() = doFastFail } object thePOJO2XMLRenderer extends POJO2XMLRenderer( true, false ) { } -- L.G. Meredith Managing Partner Biosimilarity LLC 806 55th St NE Seattle, WA 98105 +1 206.650.3740 http://biosimilarity.blogspot.com --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Lift" group. To post to this group, send email to liftweb@googlegroups.com To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/liftweb?hl=en -~----------~----~----~----~------~----~------~--~---