You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by Christian Meder <ch...@absolutegiganten.org> on 2005/11/14 08:24:40 UTC
Re: svn commit: r332894 - in /struts: build/trunk/project.xml
core/trunk/src/java/org/apache/struts/action/DynaActionFormClass.java
core/trunk/xdocs/userGuide/building_controller.xml
On Sun, 2005-11-13 at 05:30 +0000, laurieh@apache.org wrote:
> Author: laurieh
> Date: Sat Nov 12 21:30:23 2005
> New Revision: 332894
>
> URL: http://svn.apache.org/viewcvs?rev=332894&view=rev
> Log:
> iEnhancing DyanActionForm and friends to remove the need for '.map' when
> accessing properties in JSPs, as described in #36794:
>
> http://issues.apache.org/bugzilla/show_bug.cgi?id=36794
>
>
> Modified:
> struts/build/trunk/project.xml
> struts/core/trunk/src/java/org/apache/struts/action/DynaActionFormClass.java
> struts/core/trunk/xdocs/userGuide/building_controller.xml
>
> Modified: struts/build/trunk/project.xml
> URL: http://svn.apache.org/viewcvs/struts/build/trunk/project.xml?rev=332894&r1=332893&r2=332894&view=diff
> ==============================================================================
> --- struts/build/trunk/project.xml (original)
> +++ struts/build/trunk/project.xml Sat Nov 12 21:30:23 2005
> @@ -361,6 +361,16 @@
> </dependency>
>
> <dependency>
> + <groupId>cglib</groupId>
> + <artifactId>cglib-nodep</artifactId>
> + <version>2.1_3</version>
> + <url>http://cglib.sourceforge.net/</url>
> + <properties>
> + <war.bundle>true</war.bundle>
> + </properties>
> + </dependency>
> +
> + <dependency>
> <groupId>oro</groupId>
> <artifactId>oro</artifactId>
> <version>2.0.8</version>
>
> Modified: struts/core/trunk/src/java/org/apache/struts/action/DynaActionFormClass.java
> URL: http://svn.apache.org/viewcvs/struts/core/trunk/src/java/org/apache/struts/action/DynaActionFormClass.java?rev=332894&r1=332893&r2=332894&view=diff
> ==============================================================================
> --- struts/core/trunk/src/java/org/apache/struts/action/DynaActionFormClass.java (original)
> +++ struts/core/trunk/src/java/org/apache/struts/action/DynaActionFormClass.java Sat Nov 12 21:30:23 2005
> @@ -22,13 +22,24 @@
>
> import java.io.Serializable;
> import java.util.HashMap;
> +import java.util.Map;
> +import java.lang.reflect.Method;
>
> import org.apache.commons.beanutils.DynaBean;
> import org.apache.commons.beanutils.DynaClass;
> import org.apache.commons.beanutils.DynaProperty;
> +import org.apache.commons.logging.Log;
> +import org.apache.commons.logging.LogFactory;
> import org.apache.struts.config.FormBeanConfig;
> import org.apache.struts.config.FormPropertyConfig;
> import org.apache.struts.util.RequestUtils;
> +import net.sf.cglib.proxy.InterfaceMaker;
> +import net.sf.cglib.proxy.Enhancer;
> +import net.sf.cglib.proxy.MethodInterceptor;
> +import net.sf.cglib.proxy.MethodProxy;
> +import net.sf.cglib.asm.Type;
> +import net.sf.cglib.core.Signature;
> +import net.sf.cglib.core.Constants;
>
>
> /**
> @@ -45,6 +56,7 @@
>
> public class DynaActionFormClass implements DynaClass, Serializable {
>
> + private Log log = LogFactory.getLog(DynaActionFormClass.class);
>
> // ----------------------------------------------------------- Constructors
>
> @@ -181,10 +193,9 @@
> public DynaBean newInstance()
> throws IllegalAccessException, InstantiationException {
>
> - DynaActionForm dynaBean =
> - (DynaActionForm) getBeanClass().newInstance();
> - dynaBean.setDynaActionFormClass(this);
> FormPropertyConfig[] props = config.findFormPropertyConfigs();
> + DynaActionForm dynaBean = (DynaActionForm) doCreate(props);
> + dynaBean.setDynaActionFormClass(this);
> for (int i = 0; i < props.length; i++) {
> dynaBean.set(props[i].getName(), props[i].initial());
> }
> @@ -312,4 +323,112 @@
> }
>
>
> + // -------------------------------------------------------- Private Methods
> +
> + private Object doCreate(FormPropertyConfig[] props) {
> + // Build an interface to implement consisting of getter/setter
> + // pairs for each property. Also create a lookup table so we
> + // can map method names back to the corresponding dynamic
> + // property on invocation. This allows us to correctly handle
> + // property names that don't comply with JavaBeans naming
> + // conventions.
> + Map properties = new HashMap(props.length * 2);
> + InterfaceMaker im = new InterfaceMaker();
> + for (int i = 0; i < props.length; i++) {
> + String name = props[i].getName();
> + Class type = props[i].getTypeClass();
> + Type ttype = Type.getType(type);
> +
> + if (! name.matches("[\\w]+")) {
> + // Note: this allows leading digits, which is not legal
> + // for an identifier but is valid in a getter/setter
> + // method name. Since you can define such getter/setter
> + // directly, we support doing so dynamically too.
> + if (log.isWarnEnabled()) {
> + log.warn(
> + "Dyna property name '" + name +
> + "' in form bean " + config.getName() +
> + " is not a legal Java identifier. " +
> + "No property access methods generated.");
> + }
> + } else {
> + // Capitalize property name appropriately
> + String property;
> + if ((name.length() <= 1) ||
Hmm. Should we handle a name of length "0" ? If we get an empty string
I'd prefer an error instead of continuing.
> + ( Character.isLowerCase(name.charAt(0)) &&
> + (! Character.isLowerCase(name.charAt(1))))
> + ) {
> + property = name;
> + } else {
> + property =
> + Character.toUpperCase(name.charAt(0)) +
> + name.substring(1);
> + }
> +
> + // Create the getter/setter method pair
> + Signature getter = new Signature("get"+property, ttype, Constants.TYPES_EMPTY);
> + Signature setter = new Signature("set"+property, Type.VOID_TYPE, new Type[] { ttype });
> + im.add(getter, Constants.TYPES_EMPTY);
> + im.add(setter, Constants.TYPES_EMPTY);
> + properties.put("get"+property, name);
> + properties.put("set"+property, name);
> + }
> + }
> + Class beanInterface = im.create();
> +
> + // Now generate a proxy for the dyna bean that also implements
> + // the getter/setter methods defined above. We turn off the
> + // Factory interface to preven problems with BeanUtils.copyProperties
s/preven/prevent
> + // when both source and target bean are enhanced (otherwise, the
> + // target bean's callbacks get overwritten with the source beans,
> + // leading to unexpected behaviour).
> + Enhancer e = new Enhancer();
> + e.setSuperclass(beanClass);
> + e.setInterfaces(new Class[] { beanInterface });
> + e.setCallback(new BeanInterceptor(properties));
> + e.setUseFactory(false);
> +
> + // Return the generated/enhanced bean
> + return e.create();
> + }
> +
> + private static class BeanInterceptor implements MethodInterceptor, Serializable {
> + private Map propertyLookup;
> +
> + public BeanInterceptor(Map propertyLookup) {
> + this.propertyLookup = propertyLookup;
> + }
> +
> + public Object intercept(Object obj, Method method, Object[] args,
> + MethodProxy proxy) throws Throwable {
> +
> + String methodNm = method.getName();
> + String propertyNm = (String) propertyLookup.get(methodNm);
> + String targetNm = methodNm.substring(0, 3); // get/set
> +
> + if (propertyNm == null) {
> + // Not a dyna property access, just pass call along
> + return proxy.invokeSuper(obj, args);
> + }
> +
> + // Handle the dyna property access:
> + // - map getFoo(...) to get("foo", ...)
> + // - map setFoo(bar, ...) to set("foo", bar, ...)
> + Class[] targetArgTypes = new Class[args.length + 1];
> + Object[] targetArgs = new Object[args.length + 1];
> + targetArgTypes[0] = String.class; // for property name
> + targetArgs[0] = propertyNm;
> +
> + System.arraycopy(args, 0, targetArgs, 1, args.length);
> +
> + for (int i = 0; i < args.length; i++) {
> + targetArgTypes[i + 1] = args[i].getClass();
> + }
> +
> + Method target = obj.getClass().getMethod(targetNm, targetArgTypes);
> +
> + // Return the result of mapped get/set
> + return target.invoke(obj, targetArgs);
> + }
> + }
> }
>
> Modified: struts/core/trunk/xdocs/userGuide/building_controller.xml
> URL: http://svn.apache.org/viewcvs/struts/core/trunk/xdocs/userGuide/building_controller.xml?rev=332894&r1=332893&r2=332894&view=diff
> ==============================================================================
> --- struts/core/trunk/xdocs/userGuide/building_controller.xml (original)
> +++ struts/core/trunk/xdocs/userGuide/building_controller.xml Sat Nov 12 21:30:23 2005
Oh. It's one of that evil "Mix white space cleanup with doc updates
making life harder for reviewers" ;-)
Christian
--
Christian Meder, email: chris@absolutegiganten.org
The Way-Seeking Mind of a tenzo is actualized
by rolling up your sleeves.
(Eihei Dogen Zenji)
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org
Re: svn commit: r332894 - in /struts: build/trunk/project.xml core/trunk/src/java/org/apache/struts/action/DynaActionFormClass.java
core/trunk/xdocs/userGuide/building_controller.xml
Posted by Laurie Harper <la...@holoweb.net>.
Christian Meder wrote:
> Hmm. Should we handle a name of length "0" ? If we get an empty string
> I'd prefer an error instead of continuing.
I deliberately avoided making this an error because, whether it makes
sense or not ;-), an empty string is currently allowed... Seemed better
to retain compatibility.
> s/preven/prevent
Doh!
> Oh. It's one of that evil "Mix white space cleanup with doc updates
> making life harder for reviewers" ;-)
Ugg, sorry, thought I'd reverted all those.
L.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org