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
-~----------~----~----~----~------~----~------~--~---

Reply via email to