Re: Performance, Reflection, and Object Creation vs. Cacheing(was: Barracuda talk)
On Tue, 2001-08-28 at 00:02, Bryan Field-Elliot wrote: Also, you go on to say 'ditto for objection creation, and that it's more expensive to cache an object than recreate it. Where are you getting this information? It goes against the design considerations of virtually every highly optimized Java system I've seen, including EJB which goes to EXTREME lengths to reuse rather than recreate. You see the same pattern with JSP custom tags (nowadays they are pooled), and you even see the same thing in the Servlet spec design (which is to have one multithreaded instance of the servlet class, rather than one per user which would make more logical sense). Object creation is rather fast, but that doesn't mean caching is always frowned upon. Caching for performance at the enterprise level is really to reduce object initialization rather than object creation. The problem with EJBs, Tags, and Servlets is that they potentially do a lot of up front initialization. All three has to at least read an XML to load some kind of deployment information, and then there are resources (db, networking) that can be allocated by containers or developers. Struts objects generally don't a lot of object initialization, therefore isn't necessarily a really good candidate for caching. Calvin
Re: Performance, Reflection, and Object Creation vs. Cacheing
People I trust have said that they have run benchmarks that say reflection can cost 5% to 10% more than direct method invocation. http://archives.java.sun.com/cgi-bin/wa?A2=ind0001L=jsp-interestP=R35735 Now this is enough for some maven to put it on an optimization punchlist, along with unrolling loops, and other time vs space trade-offs. But, personally, I don't find the need to unroll many loops in the applications I write ;-) So it's important to ask yourself whether 5% to 10% is a difference that makes a difference? Also remember that in a real application, we are looking at one utility method, like BeanUtils.populate(), being threaded with all the assignments. I would think this is much more efficient than loading several hundred optimized methods just to manage direct method invocations. BeanUtils.populate() also caches the descriptors so subsequent calls are even cheaper than the first. Real-life optimizations are differences that make a real difference. When the EJB platform was being designed, object creation ~did~ make a difference, and caching ~was~ vital. To an extent it still is, especially with deep hierarchies, like those many EJB applications find themselves using. But object creation and garbage collection in a late model JVM is not what it used to be ;-) Progress! Meanwhile, personally, I've started to build calls to BeanUtils.populate() into my own data transfer utilities. This lets me put a call deep inside the resource layer that neatly turns an arbitrary ResultSet into a collection of arbitrary beans. It just matches the rset columns with the jbean properties. // Transfer ResultSet to Collection of target beans ** if (resultSet!=null) { collection = ResultSetUtils.getCollection( target,resultSet); } Where ResultSetUtils does this public static void populate(Object bean, ResultSet resultSet) throws SQLException { // Build a list of relevant column properties from this resultSet HashMap properties = new HashMap(); // Acquire resultSet MetaData ResultSetMetaData metaData = resultSet.getMetaData(); int cols = metaData.getColumnCount(); // Scroll to next record and pump into hashmap if (resultSet.next()) for (int i=1; i=cols ; i++) { // :TODO: Let native types through /* int type = metaData.getType(i); if ... properties.put(metaData.getColumnName(i), resultSet.getObject(i)); else */ properties.put(metaData.getColumnName(i), resultSet.getString(i)); } // Set the corresponding properties of our bean try { BeanUtils.populate(bean, properties); } catch (Exception e) { throw new SQLException(BeanUtils.populate threw + e.toString()); } } This can save hundreds of lines of code that would have otherwise have been needed to write custom transfer utilities. (Been there, did that, not fun.) Of course, it works with more than just ResultSets. I wrote a similar set of utilities last week that turned a Lucene Hits list into a collection of beans. Sweet ;-) Here are some other links from this list: http://www.mail-archive.com/struts-user@jakarta.apache.org/msg12574.html http://www.mail-archive.com/struts-user@jakarta.apache.org/msg13847.html http://www.mail-archive.com/struts-user@jakarta.apache.org/msg13294.html http://www.mail-archive.com/struts-user@jakarta.apache.org/msg13149.html http://www.mail-archive.com/struts-user@jakarta.apache.org/msg11933.html http://www.mail-archive.com/struts-user@jakarta.apache.org/msg02683.html http://www.mail-archive.com/struts-user@jakarta.apache.org/msg00374.html Other background links: http://java.sun.com/j2se/1.4/docs/guide/reflection/ http://www-106.ibm.com/developerworks/library/introspect/index.html http://www.javaworld.com/javaworld/jw-11-1999/jw-11-servlet_p.html http://www.javaworld.com/javaworld/jw-11-1998/jw-11-batch_p.html http://www.ddj.com/articles/1998/9801/9801c/9801c.htm http://www.javaworld.com/javaworld/jw-09-1997/jw-09-indepth_p.html Today's quote: We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. - Donald Knuth -T. Bryan Field-Elliot wrote: This is incredibly important stuff! I'm sick to death of making tons of EJB entity beans, and then Value Objects (or data objects) which are very similar, and with Struts, Form Beans which again are very similar. Often I wish I could just use generic property sets (using HashMap, or any other generic collection). But I have resisted on principle, because I thought it would be a poor performer compared to straight Java variables and getters and setters. But here you are saying reflection is no longer a point of concern. What information have you got in this regard?
RE: Can BeanUtils support Timestamp datatype? (was: Performance,Reflection, and Object Creation vs. Cacheing)
Ted, Wow! I have to thank you for saving me from typing hundreds of lines of code (well, I already wrote them -- now i'm gladly going to rip them out!) Using BeanUtils to set properties of a bean from the column name of a ResultSet is really smart. I've used your code fragment and it works great. However, I noticed the TODO: says to let native types through. I would like to help out on this part -- since I have a Timestamp datatype in my beans. Now, are there any plans to make BeanUtils support setting a Timestamp method? How would I go about writing an extension to BeanUtils to support different datatypes? I guess if I can't figure out how to set Timestamp datatypes in my beans, I'll just change it to a string. Mindaugas Idzelis -Original Message- From: Ted Husted [mailto:[EMAIL PROTECTED]] Sent: Tuesday, August 28, 2001 9:46 AM To: [EMAIL PROTECTED] Subject: Re: Performance, Reflection, and Object Creation vs. Cacheing snip Meanwhile, personally, I've started to build calls to BeanUtils.populate() into my own data transfer utilities. This lets me put a call deep inside the resource layer that neatly turns an arbitrary ResultSet into a collection of arbitrary beans. It just matches the rset columns with the jbean properties. // Transfer ResultSet to Collection of target beans ** if (resultSet!=null) { collection = ResultSetUtils.getCollection( target,resultSet); } Where ResultSetUtils does this public static void populate(Object bean, ResultSet resultSet) throws SQLException { // Build a list of relevant column properties from this resultSet HashMap properties = new HashMap(); // Acquire resultSet MetaData ResultSetMetaData metaData = resultSet.getMetaData(); int cols = metaData.getColumnCount(); // Scroll to next record and pump into hashmap if (resultSet.next()) for (int i=1; i=cols ; i++) { // :TODO: Let native types through /* int type = metaData.getType(i); if ... properties.put(metaData.getColumnName(i), resultSet.getObject(i)); else */ properties.put(metaData.getColumnName(i), resultSet.getString(i)); } // Set the corresponding properties of our bean try { BeanUtils.populate(bean, properties); } catch (Exception e) { throw new SQLException(BeanUtils.populate threw + e.toString()); } } This can save hundreds of lines of code that would have otherwise have been needed to write custom transfer utilities. (Been there, did that, not fun.) Of course, it works with more than just ResultSets. I wrote a similar set of utilities last week that turned a Lucene Hits list into a collection of beans. Sweet ;-) snip
Re: Performance, Reflection, and Object Creation vs. Cacheing
Thanks for the insights Ted, Please help me if I'm misinterpreting. But looking at your code, it seems like your populate still takes a plain Bean as it's destination, although it can use a property set (in this case, a ResultSet) as the source. This reduces the proliferation of Value (or other Bean) classes by 50%, but not 100%. In your scenario, which set of beans still need to be developed as plain old beans rather than dynamic sets of properties (e.g. the Entity beans, the Value Objects, or the Struts Form Beans, etc?)? Thanks, Bryan Ted Husted wrote: public static void populate(Object bean, ResultSet resultSet)
Re: Performance, Reflection, and Object Creation vs. Cacheing
To close the loop, it's helpful if a JavaBean can provide a Map of itself. This way you can do things like BeanUtils.populate(beanTarget,beanSource.toMap()). So I tend to define an interface that requires that and apply it to all my beans, regardless of role. One consequence is that this will populate the properties that match, and ignore any property that doesn't, so you don't have any parity checking between the source and target. Though, usually this is a Good Thing. For example, you can use the same bean class for a list and for the detail, and just leave most of the properties null when it is being used on the list. Bryan Field-Elliot wrote: Thanks for the insights Ted, Please help me if I'm misinterpreting. But looking at your code, it seems like your populate still takes a plain Bean as it's destination, although it can use a property set (in this case, a ResultSet) as the source. This reduces the proliferation of Value (or other Bean) classes by 50%, but not 100%. In your scenario, which set of beans still need to be developed as plain old beans rather than dynamic sets of properties (e.g. the Entity beans, the Value Objects, or the Struts Form Beans, etc?)? Thanks, Bryan
RE: Performance, Reflection, and Object Creation vs. Cacheing
Ted, Wow! I have to thank you for saving me from typing hundreds of lines of code (well, I already wrote them -- now i'm gladly going to rip them out!) Using BeanUtils to set properties of a bean from the column name of a ResultSet is really smart. I've used your code fragment and it works great. However, I noticed the TODO: says to let native types through. I would like to help out on this part -- since I have a Timestamp datatype in my beans. Now, are there any plans to make BeanUtils support setting a Timestamp method? How would I go about writing an extension to BeanUtils to support different datatypes? I guess if I can't figure out how to set Timestamp datatypes in my beans, I'll just change it to a string. Mindaugas Idzelis -Original Message- From: Ted Husted [mailto:[EMAIL PROTECTED]] Sent: Tuesday, August 28, 2001 9:46 AM To: [EMAIL PROTECTED] Subject: Re: Performance, Reflection, and Object Creation vs. Cacheing snip Meanwhile, personally, I've started to build calls to BeanUtils.populate() into my own data transfer utilities. This lets me put a call deep inside the resource layer that neatly turns an arbitrary ResultSet into a collection of arbitrary beans. It just matches the rset columns with the jbean properties. // Transfer ResultSet to Collection of target beans ** if (resultSet!=null) { collection = ResultSetUtils.getCollection( target,resultSet); } Where ResultSetUtils does this public static void populate(Object bean, ResultSet resultSet) throws SQLException { // Build a list of relevant column properties from this resultSet HashMap properties = new HashMap(); // Acquire resultSet MetaData ResultSetMetaData metaData = resultSet.getMetaData(); int cols = metaData.getColumnCount(); // Scroll to next record and pump into hashmap if (resultSet.next()) for (int i=1; i=cols ; i++) { // :TODO: Let native types through /* int type = metaData.getType(i); if ... properties.put(metaData.getColumnName(i), resultSet.getObject(i)); else */ properties.put(metaData.getColumnName(i), resultSet.getString(i)); } // Set the corresponding properties of our bean try { BeanUtils.populate(bean, properties); } catch (Exception e) { throw new SQLException(BeanUtils.populate threw + e.toString()); } } This can save hundreds of lines of code that would have otherwise have been needed to write custom transfer utilities. (Been there, did that, not fun.) Of course, it works with more than just ResultSets. I wrote a similar set of utilities last week that turned a Lucene Hits list into a collection of beans. Sweet ;-) snip
Performance, Reflection, and Object Creation vs. Cacheing (was: Barracuda talk)
Ted, I read your rebuttal tonight re: Barracuda, and I have questions about one of your points. Actually this has nothing to do with Barracuda: - Reflection Every recent report I've seen says reflection is no longer a point of concern. Ditto for object creation and garbage collection. The latest advice is that is can be more expensive to cache an object that recreate it. - This is incredibly important stuff! I'm sick to death of making tons of EJB entity beans, and then Value Objects (or data objects) which are very similar, and with Struts, Form Beans which again are very similar. Often I wish I could just use generic property sets (using HashMap, or any other generic collection). But I have resisted on principle, because I thought it would be a poor performer compared to straight Java variables and getters and setters. But here you are saying reflection is no longer a point of concern. What information have you got in this regard? Also, you go on to say 'ditto for objection creation, and that it's more expensive to cache an object than recreate it. Where are you getting this information? It goes against the design considerations of virtually every highly optimized Java system I've seen, including EJB which goes to EXTREME lengths to reuse rather than recreate. You see the same pattern with JSP custom tags (nowadays they are pooled), and you even see the same thing in the Servlet spec design (which is to have one multithreaded instance of the servlet class, rather than one per user which would make more logical sense). So, my apologies if this is off-topic of Struts, but these seem like very important and impactful design issues, relevent (even if peripherally) to good Struts design and development. Thanks, Bryan