- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
generic programming question
Thu, 2009-03-05, 23:01
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
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
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