Fwd: [Laszlo-dev] PATCH: Correct handling of javabeans as return objects

Eric Bloch bloch at laszlosystems.com
Mon Jan 31 14:48:37 PST 2005


Henry and Markus,

Some questions since I'm not up on commons-beanutils.  Apologies for the 
seemingly admin-a-tron type questions here...


1) What version of beanutils is this?

2) A quick glance shows beanutils to depend on the evil commons-logging 
jar.   This will increase our continued dependence on commons-logging, 
which is a known problem for container compatibility.  A real qa of this 
change will require full container and jre compatibility runs.

3) Would the version in tomcat work ok if the class loader chose it 
instead of ours?

-Eric




Henry Minsky wrote:
> This patch looks fine, but I am wondering how to handle the dependence
> on the commons-beanutils.jar file. It seems like that jar file is
> shipped with Tomcat in its server/lib  directory, so if we copy some
> version of this jar into WEB-INF/lib, will there be any potential
> conflicts between the LPS and some other version of Tomcat or other
> servlet container?
> 
> 
> 
> ---------- Forwarded message ----------
> From: freaquac <jocsch at freaquac.de>
> Date: Sun, 21 Nov 2004 20:00:59 +0100
> Subject: [Laszlo-dev] PATCH: Correct handling of javabeans as return objects
> To: laszlo-dev at openlaszlo.org
> 
> 
> Hi list,
> do you ever used the <javarpc> calls and inspected  the laszlo converted
> return object? Laszlo converts, at least in the 2.2 release (I don't have
> tried 3.0 yet, maybe someone changed this behaviour already), only the public
> fields of an object into xml and send them to the swf client.
> 
> That's pretty annoying because nobody (or not many) in the OO world use public
> member fields. Instead it's normal to provide access via public getter and
> setter methods. See the javabeans standard.
> 
> Because I didn't want to write a DTO for every object I have, I modified the
> sourcecode of the LZReturnObject to inspect the given return object with the
> help of the jakarta-commons beanutils
> ( http://jakarta.apache.org/commons/beanutils/ )
> Now the LZReturnObject converts the object according to the javabean
> specifications (that means it uses the public getters instead of accessing
> the fields).
> 
> Maybe a developer can check this patch and apply it to cvs?
> To compile the changed file it's neccessary to copy the commons-beanutils.jar
> to the WEB-INF/lib directory (I use version 1.6.1)
> 
> Greetings,
>  Markus Joschko
> 
> I added a patch against the 2.2 version of LZReturnObject.java and the
> modified LZReturnObject
> 
> 
> _______________________________________________
> Laszlo-dev mailing list
> Laszlo-dev at openlaszlo.org
> http://www.openlaszlo.org/mailman/listinfo/laszlo-dev
> 
> 
> ------------------------------------------------------------------------
> 
> 28d27
> < import org.apache.commons.beanutils.PropertyUtils;
> 136,166c135,156
> < 	Map beanProps = null;
> < 	try {
> < 	    //Use jakarta-commons beanutils to inspect the object
> < 	    beanProps = PropertyUtils.describe(object);
> < 	} catch (IllegalAccessException e) {
> < 	    mLogger.error("IllegalAccessException",e);
> < 	} catch (InvocationTargetException e) {
> < 	    mLogger.error("InvocationTargetException",e);
> < 	} catch (NoSuchMethodException e) {
> < 	    mLogger.error("NoSuchMethodException",e);
> < 	}
> < 					
> < 	if(beanProps != null) {
> < 	    Set keys = beanProps.keySet();
> < 	    Iterator iter = keys.iterator();
> < 	    while(iter.hasNext()){
> < 	        String fieldName  = (String)iter.next();
> < 		//Don't add the class property as it is already set by the method
> < 		if(!"class".equals(fieldName)) {
> < 		    Object value = beanProps.get(fieldName);
> < 
> <                     mLogger.debug("add field name " + fieldName + ", " +((value!=null)?value.getClass():null));
> < 		    mProgram.push(varname);
> < 		    mProgram.getVar();
> < 		    mProgram.push((String)fieldName);
> < 		    createReturnValue(value);
> < 		    mBody.writeByte(Actions.SetMember);
> < 		}
> < 	    }
> < 	}
> < 	 
> ---
> 
>>        Field[] fields = cl.getFields();
>>        for (int i=0; i < fields.length; i++) {
>>            if (! Modifier.isPublic(fields[i].getModifiers()))
>>                continue;
>>
>>            String fieldName = fields[i].getName();
>>            Object value;
>>            try {
>>                value = fields[i].get(object);
>>            } catch (IllegalAccessException e) {
>>                mLogger.error("IllegalAccessException", e);
>>                continue;
>>            }
>>
>>            mLogger.debug("add field name " + fieldName + ", " + value.getClass());
>>            mProgram.push(varname);
>>            mProgram.getVar();
>>            mProgram.push(fieldName);
>>            createReturnValue(value);
>>            mBody.writeByte(Actions.SetMember);
>>        }
>>
> 
> 
> 
> ------------------------------------------------------------------------
> 
> /******************************************************************************
>  * LZReturnObject.java
>  * ****************************************************************************/
> 
> //LZ_JAVA_COPYRIGHT_BEGIN
> /* *****************************************************************************
> * Copyright (c) 2001-2004 Laszlo Systems, Inc.
> * All Rights Reserved.
> *
> * This software is the proprietary information of Laszlo Systems, Inc.
> * Use is subject to license terms.
> *
> * ****************************************************************************/
> //LZ_JAVA_COPYRIGHT_END
> 
> package com.laszlosystems.remote;
> 
> import java.io.*;
> import java.util.*;
> import java.lang.reflect.*;
> import javax.servlet.http.*;
> import com.laszlosystems.iv.flash.util.*;
> import com.laszlosystems.iv.flash.api.action.*;
> import com.laszlosystems.iv.flash.api.*;
> import com.laszlosystems.utils.*;
> import com.laszlosystems.xml.internal.*;
> import org.apache.log4j.*;
> import org.apache.commons.beanutils.PropertyUtils;
> 
> /**
>  * Utility class to create object SWF based on a server object.
>  */
> public class LZReturnObject
> {
>     public static Logger mLogger = Logger.getLogger(LZReturnObject.class);
> 
>     int mCount = 0;
>     int mSize = 4096;
>     FlashBuffer mBody = new FlashBuffer(mSize);
>     Program mProgram = new Program(mBody);
>     DataContext mDC = new DataContext();
> 
> 
>     void pushInteger(int i) {
>         mLogger.debug("pushInteger");
>         mProgram.push(i);
>     }
> 
>     void pushFloat(float f) {
>         mLogger.debug("pushFloat");
>         mProgram.push(f);
>     }
> 
>     void pushString(String s) {
>         mLogger.debug("pushString");
>         DataCommon.pushStringData(s, mBody, mDC);
> //        mProgram.push(s);
>     }
> 
>     void pushDouble(double d) {
>         mLogger.debug("pushDouble");
>         mBody.writeByte(Actions.PushData);
>         mBody.writeWord(8+1);
>         mBody.writeByte(6);
>         long dbits = Double.doubleToLongBits(d);
>         mBody.writeDWord((int)(dbits>>>32));
>         mBody.writeDWord((int)(dbits&0xffffffffL));
>     }
> 
> 
>     void pushBoolean(boolean b) {
>         mLogger.debug("pushBoolean");
>         mBody.writeByte(Actions.PushData);
>         mBody.writeWord(1+1);
>         mBody.writeByte(5);
>         mBody.writeByte(b?1:0);
>     }
> 
>     void pushArray(Object object) {
>         mLogger.debug("pushArray");
>         int length = Array.getLength(object);
>         for (int i = length - 1; 0 <= i; i--) {
>             createReturnValue(Array.get(object, i));
>         }
>         mProgram.push(length);
>         mBody.writeByte(Actions.InitArray);
>     }
> 
>     void pushList(Object object) {
>         mLogger.debug("pushList");
>         List list = (List)object;
>         int length = list.size();
>         for (int i = length - 1; 0 <= i; i--) {
>             createReturnValue(list.get(i));
>         }
>         mProgram.push(length);
>         mBody.writeByte(Actions.InitArray);
>     }
> 
>     void pushNull() {
>         mBody.writeByte(Actions.PushData);
>         mBody.writeWord(0+1);
>         mBody.writeByte(2);
>     }
> 
> 
>     void pushObject(Object object) {
>         Class cl = object.getClass();
> 
>         // Does this have to be a unique name?
>         String varname = "__tmp" + (mCount++);
>         String classname = cl.getName();
> 
>         //------------------------------------------------------------
>         // varname = new Object();
>         mProgram.push(varname);
>         {
>             // new Object()
>             mProgram.push(0);        // zero arguments
>             mProgram.push("Object"); // push classname
>             mProgram.newObject();    // instantiate
>         }
>         mProgram.setVar();
> 
> 
>         //------------------------------------------------------------
>         // varname.class = classname
>         mProgram.push(varname);
>         mProgram.getVar();
>         mProgram.push("class");
>         mProgram.push(classname);
>         mBody.writeByte(Actions.SetMember);
> 
>         //------------------------------------------------------------
>         // Just get the fields from the objects and add it to this object
> 	Map beanProps = null;
> 	try {
> 	    //Use jakarta-commons beanutils to inspect the object
> 	    beanProps = PropertyUtils.describe(object);
> 	} catch (IllegalAccessException e) {
> 	    mLogger.error("IllegalAccessException",e);
> 	} catch (InvocationTargetException e) {
> 	    mLogger.error("InvocationTargetException",e);
> 	} catch (NoSuchMethodException e) {
> 	    mLogger.error("NoSuchMethodException",e);
> 	}
> 					
> 	if(beanProps != null) {
> 	    Set keys = beanProps.keySet();
> 	    Iterator iter = keys.iterator();
> 	    while(iter.hasNext()){
> 	        String fieldName  = (String)iter.next();
> 		//Don't add the class property as it is already set by the method
> 		if(!"class".equals(fieldName)) {
> 		    Object value = beanProps.get(fieldName);
> 
>                     mLogger.debug("add field name " + fieldName + ", " +((value!=null)?value.getClass():null));
> 		    mProgram.push(varname);
> 		    mProgram.getVar();
> 		    mProgram.push((String)fieldName);
> 		    createReturnValue(value);
> 		    mBody.writeByte(Actions.SetMember);
> 		}
> 	    }
> 	}
> 	 
>         //------------------------------------------------------------
>         // add varname object into stack
>         mProgram.push(varname);
>         mProgram.getVar();
>     }
> 
>     void pushMap(Map map) {
> 
>         // Does this have to be a unique name?
>         String varname = "__tmp" + (mCount++);
> 
>         //------------------------------------------------------------
>         // varname = new Object();
>         mProgram.push(varname);
>         {
>             // new Object()
>             mProgram.push(0);        // zero arguments
>             mProgram.push("Object"); // push classname
>             mProgram.newObject();    // instantiate
>         }
>         mProgram.setVar();
> 
>         Iterator iter = map.keySet().iterator();
> 
>         while (iter.hasNext()) {
>             String key = (String)iter.next();
> 
>             //------------------------------------------------------------
>             // varname.class = classname
>             mProgram.push(varname);
>             mProgram.getVar();
>             mProgram.push(key);
>             createReturnValue(map.get(key));
>             mBody.writeByte(Actions.SetMember);
>         }
> 
> 
>         //------------------------------------------------------------
>         // add varname object into stack
>         mProgram.push(varname);
>         mProgram.getVar();
>     }
> 
>     /**
>      * Recurse through this function to create return value
>      */
>     void createReturnValue(Object object) {
>         mLogger.debug("createReturnValue");
>         if (object == null) {
>             pushNull();
>             return;
>         }
> 
>         Class cl = object.getClass();
>         if (cl.isArray()) {
>             pushArray(object);
>         } else if (List.class.isInstance(object)) {
>             pushList(object);
>         } else if (Map.class.isInstance(object)) {
>             pushMap((Map)object);
>  	} else if (cl == Integer.class) {
>             pushInteger(((Integer)object).intValue());
>         } else if (cl == Long.class) {
>             //------------------------------------------------------------
>             // From: http://developer.irt.org/script/1031.htm
>             //
>             // In JavaScript all numbers are floating-point numbers.
>             //
>             // JavaScript uses the standard 8 byte IEEE floating-point numeric
>             // format, which means the range is from:
>             //
>             // +/- 1.7976931348623157x10^308 - very large, and +/- 5x10^-324 -
>             // very small.
>             //
>             // As JavaScript uses floating-point numbers the accuracy is only
>             // assured for integers between: -9,007,199,254,740,992 (-2^53) and
>             // 9,007,199,254,740,992 (2^53)
>             //
>             // All the above from "JavaScript The Definitive Guide" - O'Reilly. 
>             // 
>             //------------------------------------------------------------
>             // Java long:
>             // 8 bytes signed (two's complement). Ranges from
>             // -9,223,372,036,854,775,808 to +9,223,372,036,854,775,807.
>             //------------------------------------------------------------
>             
>             // possible rounding inaccuracy
>             pushInteger(((Long)object).intValue());
> 
>         } else if (cl == Short.class) {
>             pushInteger(((Short)object).intValue());
>         } else if (cl == Byte.class) {
>             // push as number for now
>             pushInteger(((Byte)object).intValue());
>         } else if (cl == Character.class) {
>             pushString(((Character)object).toString());
>         } else if (cl == Float.class) {
>             pushFloat(((Float)object).floatValue());
>         } else if (cl == Double.class) {
>             pushDouble(((Double)object).doubleValue());
>         } else if (cl == Boolean.class) {
>             pushBoolean(((Boolean)object).booleanValue());
>         } else if (cl == String.class) {
>             pushString((String)object);
>         } else {
>             pushObject(object);
>         }
>     }
> 
> 
>     /**
>      *
>      */
>     public Program createObjectProgram(Object object) {
>         mLogger.debug("createObjectProgram(" + object + ")" );
> 
>         createReturnValue(object);
> 
>         //------------------------------------------------------------
>         // call into the viewsystem
>         mProgram.push("this");
>         mProgram.getVar();
>         mProgram.push(2);
>         mProgram.push("_parent");
>         mProgram.getVar();
>         mProgram.push("loader");
>         mBody.writeByte(Actions.GetMember);
>         mProgram.push("returnData");
>         mProgram.callMethod();
>         mProgram.pop();
> 
>         // Borrowed from DataCompiler. -pk
> 
>         // Collect the string dictionary data
>         byte pooldata[] = DataCommon.makeStringPool(mDC);
> 
>         // Room at the end of the buffer for maybe some callback code to the
>         // runtime to say we're done.
>         final int MISC = 4096;
> 
>         // 'out' is the main FlashBuffer for composing the output file
>         FlashBuffer out = new FlashBuffer(mBody.getSize() + pooldata.length + MISC);
>         // Write out string constant pool
>         out._writeByte( Actions.ConstantPool );
>         out._writeWord( pooldata.length + 2 ); // number of bytes in pool data + int (# strings)
>         out._writeWord( mDC.cpool.size() ); // number of strings in pool
>         out.writeArray( pooldata, 0, pooldata.length); // copy the data
> 
>         // Write out the code to build nodes
>         out.writeArray(mBody.getBuf(), 0, mBody.getSize());
>         return new Program(out);
>     }
> 
> 
>     /**
>      */
>     public static FlashFile createObjectFile(Object object)
>         throws IOException {
>         mLogger.debug("createObjectFile(" + object + ")" );
>         // Create FlashFile object nd include action bytes
>         FlashFile file = FlashFile.newFlashFile();
>         Script s = new Script(1);
>         file.setMainScript(s);
>         file.setVersion(5);
>         Frame frame = s.newFrame();
>         Program program = new LZReturnObject().createObjectProgram(object);
>         frame.addFlashObject(new DoAction(program));
>         return file;
>     }
> 
>     /**
>      */
>     public static byte[] createObject(Object object)
>         throws IOException {
>         mLogger.debug("createObject(" + object + ")" );
> 
>         int i = 0;
>         try {
>             FlashFile file = createObjectFile(object);
>             FlashOutput fob = file.generate();
>             byte[] buf = new byte[fob.getSize()];
>             System.arraycopy(fob.getBuf(), 0, buf, 0, fob.getSize());
>             return buf;
>         } catch (IVException e) {
>             throw new ChainedException(e);
>         } catch (IOException e) {
>             mLogger.error("io error creating object SWF: " + e.getMessage());
>             throw e;
>         }
>     }
> 
> }
> 
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> Laszlo-dev mailing list
> Laszlo-dev at openlaszlo.org
> http://www.openlaszlo.org/mailman/listinfo/laszlo-dev


More information about the Laszlo-dev mailing list