Uploaded image for project: 'Struts 2'
  1. Struts 2
  2. WW-4105

Struts2 raise java.lang.ClassCastException when Result type is chain

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 2.3.14.3
    • Fix Version/s: 2.5.12
    • Component/s: Core Interceptors
    • Labels:
      None
    • Environment:

      tomcat6 struts2.3.*

      Description

      java.lang.ClassCastException: A action cannot be cast to B action when A chain to B.

      ChainingInterceptor.java has a bug in intercept function when Result type is chain.

      Intercept function of ChainingInterceptor will change action member of DefaultActionInvocation class. And invokeAction of DefaultActionInvocation will fail in line 450.

      My action class has a annotation. It is org.springframework.transaction.annotation.Transactional. Action work good if it has not org.springframework.transaction.annotation.Transactional

      AtestAction.java:

      package demo.action;
      import org.apache.struts2.convention.annotation.Action;
      import org.apache.struts2.convention.annotation.ParentPackage;
      import org.apache.struts2.convention.annotation.Result;
      import org.apache.struts2.convention.annotation.Results;
      import org.springframework.context.annotation.Scope;
      import org.springframework.stereotype.Service;
      import org.springframework.transaction.annotation.Transactional;
      @Transactional
      @ParentPackage(value="swordlite")
      @Service("AtestAction")
      @Scope(value = "prototype")
      @Results( {
      @Result(name = "test", location = "testb", type = "chain",
      params = { 
      "defineId", "${_defineId}", 
      "rp", "${_resultPage}"}
      )
      })
      public class AtestAction {
      @Action(value = "/testa")
      public String run() throws Exception
      { return "test"; }
      }
      BtestAction.java:
      import org.apache.struts2.convention.annotation.Action;
      import org.apache.struts2.convention.annotation.ParentPackage;
      import org.apache.struts2.convention.annotation.Result;
      import org.apache.struts2.convention.annotation.Results;
      import org.springframework.context.annotation.Scope;
      import org.springframework.stereotype.Service;
      import org.springframework.transaction.annotation.Transactional;
      @Transactional
      @ParentPackage(value="swordlite")
      @Service("BtestAction")
      @Scope(value="prototype")
      @Results({
      @Result(name="ok", location="/ok.jsp", type="dispatcher"), 
      })
      public class BtestAction {
      @Action(value = "/testb")
      public String run() throws Exception
      { return "ok"; }
      }
      

      request: http://localhost:8080/test/testa.action
      raise error: java.lang.ClassCastException: demo.action.AtestAction cannot be cast to demo.action.BtestAction
      spring config file: applicationContext.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
      xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
      xmlns:util="http://www.springframework.org/schema/util" xmlns="http://www.springframework.org/schema/p"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd 
      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd 
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 
      http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">
      <context:component-scan base-package="..action,.**.spring" />
      <context:annotation-config />
      <aop:aspectj-autoproxy proxy-target-class="true"/>
      <bean id="propertyConfigurer"
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
      <property name="locations">
      <list>
      <value>WEB-INF/config/db.properties</value>
      <value>WEB-INF/config/hibernate.properties</value>
      </list>
      </property>
      </bean>
      <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
      destroy-method="close">
      <property name="driverClass" value="${database.working.driver}"></property>
      <property name="jdbcUrl" value="${database.working.url}"></property>
      <property name="user" value="${database.working.user}"></property>
      <property name="password" value="${database.working.password}"></property>
      <property name="maxPoolSize" value="${database.working.poolsize}"></property>
      <property name="minPoolSize" value="1"></property>
      <property name="initialPoolSize" value="1"></property>
      <property name="maxIdleTime" value="20"></property>
      </bean>
      <bean id="sessionFactory"
      class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
      <property name="dataSource" ref="dataSource" />
      <property name="packagesToScan">
      <list>
      <value>.*.model</value>
      </list>
      </property>
      <property name="hibernateProperties">
      <props>
      <prop key="hibernate.dialect">${hibernate.dialect}</prop>
      <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
      <prop key="hibernate.hbm2ddl.auto">none</prop>
      </props>
      </property>	
      </bean>
      <bean id="transactionManager"
      class="org.springframework.orm.hibernate3.HibernateTransactionManager">
      <property name="sessionFactory" ref="sessionFactory"></property>
      </bean>
      <tx:annotation-driven transaction-manager="transactionManager" />
      </beans>
      

      struts config file: struts.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE struts PUBLIC
      "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
      "http://struts.apache.org/dtds/struts-2.3.dtd">
      <struts>
      <!-- <constant name="struts.objectFactory" value="spring" /> -->
      <constant name="struts.objectFactory" value="org.apache.struts2.spring.StrutsSpringObjectFactory" />
      <constant name="struts.devMode" value="false" />
      <package name="swordlite" namespace="/" extends="struts-default">
      <global-results>
      <result name="myerror">/mrg/error.jsp</result>
      <result name="re2Editpage">/mrg/re2Editpage.jsp</result>
      </global-results>
      <global-exception-mappings>
      <exception-mapping result="re2Editpage" exception="org.hibernate.PropertyValueException"></exception-mapping>
      </global-exception-mappings>
      </package>
      </struts>
      

      stacktrace:

      java.lang.ClassCastException: demo.action.AtestAction cannot be cast to demo.action.BtestAction
      	at demo.action.BtestAction$$FastClassByCGLIB$$4c9ad5d.invoke(<generated>) ~[com.springsource.net.sf.cglib-2.2.0.jar:na]
      	at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191) ~[com.springsource.net.sf.cglib-2.2.0.jar:na]
      	at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:688) ~[org.springframework.aop-3.0.5.RELEASE.jar:3.0.5.RELEASE]
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) ~[org.springframework.aop-3.0.5.RELEASE.jar:3.0.5.RELEASE]
      	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) ~[org.springframework.transaction-3.0.5.RELEASE.jar:3.0.5.RELEASE]
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) ~[org.springframework.aop-3.0.5.RELEASE.jar:3.0.5.RELEASE]
      	at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:621) ~[org.springframework.aop-3.0.5.RELEASE.jar:3.0.5.RELEASE]
      	at demo.action.BtestAction$$EnhancerByCGLIB$$cb3cf5cd.run(<generated>) ~[com.springsource.net.sf.cglib-2.2.0.jar:na]
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_29]
      	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.6.0_29]
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.6.0_29]
      	at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.6.0_29]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:450) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:289) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:252) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256) ~[struts2-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:176) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68) ~[struts2-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:249) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:249) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73) ~[struts2-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91) ~[struts2-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:252) ~[struts2-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:176) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164) ~[struts2-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:193) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:187) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54) ~[struts2-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.ActionChainResult.execute(ActionChainResult.java:233) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:371) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:275) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256) ~[struts2-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:176) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68) ~[struts2-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:249) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:249) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73) ~[struts2-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91) ~[struts2-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:252) ~[struts2-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:176) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164) ~[struts2-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:193) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:187) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) ~[xwork-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54) ~[struts2-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:546) ~[struts2-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.struts2.dispatcher.FilterDispatcher.doFilter(FilterDispatcher.java:434) [struts2-core-2.3.14.3.jar:2.3.14.3]
      	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) [catalina.jar:6.0.35]
      	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:6.0.35]
      	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) [catalina.jar:6.0.35]
      	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) [catalina.jar:6.0.35]
      	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) [catalina.jar:6.0.35]
      	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [catalina.jar:6.0.35]
      	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [catalina.jar:6.0.35]
      	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293) [catalina.jar:6.0.35]
      	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859) [tomcat-coyote.jar:6.0.35]
      	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602) [tomcat-coyote.jar:6.0.35]
      	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) [tomcat-coyote.jar:6.0.35]
      	at java.lang.Thread.run(Unknown Source) [na:1.6.0_29]
      
      1. WW-4105.patch
        9 kB
        Yasser Zamani
      2. test.zip
        5 kB
        zhouyong
      3. struts2-debug.tar.gz
        8 kB
        Yasser Zamani
      4. lib.zip.008
        3.79 MB
        zhouyong
      5. lib.zip.007
        5.00 MB
        zhouyong
      6. lib.zip.006
        5.00 MB
        zhouyong
      7. lib.zip.005
        5.00 MB
        zhouyong
      8. lib.zip.004
        5.00 MB
        zhouyong
      9. lib.zip.003
        5.00 MB
        zhouyong
      10. lib.zip.002
        5.00 MB
        zhouyong
      11. lib.zip.001
        5.00 MB
        zhouyong

        Issue Links

          Activity

          Hide
          lukaszlenart Lukasz Lenart added a comment -

          Could you share you setup? Or prepare small maven based app which presents the bug?

          I have tested with the Struts2 Showcase application (there is example how to use action chaining) and everything works like charm

          Show
          lukaszlenart Lukasz Lenart added a comment - Could you share you setup? Or prepare small maven based app which presents the bug? I have tested with the Struts2 Showcase application (there is example how to use action chaining) and everything works like charm
          Hide
          maurizio.cucchiara Maurizio Cucchiara added a comment -

          In addition to Lukasz's requests, could you please attach the whole stacktrace?

          Show
          maurizio.cucchiara Maurizio Cucchiara added a comment - In addition to Lukasz's requests, could you please attach the whole stacktrace?
          Hide
          zeroyet zhouyong added a comment -

          My action class has a annotation. It is org.springframework.transaction.annotation.Transactional. Action work good if it has not org.springframework.transaction.annotation.Transactional

          AtestAction.java:

          package demo.action;

          import org.apache.struts2.convention.annotation.Action;
          import org.apache.struts2.convention.annotation.ParentPackage;
          import org.apache.struts2.convention.annotation.Result;
          import org.apache.struts2.convention.annotation.Results;
          import org.springframework.context.annotation.Scope;
          import org.springframework.stereotype.Service;
          import org.springframework.transaction.annotation.Transactional;

          @Transactional
          @ParentPackage(value="swordlite")
          @Service("AtestAction")
          @Scope(value = "prototype")
          @Results( {
          @Result(name = "test", location = "testb", type = "chain",
          params = {
          "defineId", "${_defineId}",
          "rp", "${_resultPage}"}
          )
          })
          public class AtestAction {
          @Action(value = "/testa")
          public String run() throws Exception

          { return "test"; }

          }

          BtestAction.java:
          import org.apache.struts2.convention.annotation.Action;
          import org.apache.struts2.convention.annotation.ParentPackage;
          import org.apache.struts2.convention.annotation.Result;
          import org.apache.struts2.convention.annotation.Results;
          import org.springframework.context.annotation.Scope;
          import org.springframework.stereotype.Service;
          import org.springframework.transaction.annotation.Transactional;

          @Transactional
          @ParentPackage(value="swordlite")
          @Service("BtestAction")
          @Scope(value="prototype")
          @Results({
          @Result(name="ok", location="/ok.jsp", type="dispatcher"),
          })
          public class BtestAction {
          @Action(value = "/testb")
          public String run() throws Exception

          { return "ok"; }

          }

          request: http://localhost:8080/test/testa.action
          raise error: java.lang.ClassCastException: demo.action.AtestAction cannot be cast to demo.action.BtestAction

          spring config file: applicationContext.xml
          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
          xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
          xmlns:util="http://www.springframework.org/schema/util" xmlns="http://www.springframework.org/schema/p"
          xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
          http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
          http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

          <context:component-scan base-package="..action,.**.spring" />
          <context:annotation-config />
          <aop:aspectj-autoproxy proxy-target-class="true"/>
          <bean id="propertyConfigurer"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
          <property name="locations">
          <list>
          <value>WEB-INF/config/db.properties</value>
          <value>WEB-INF/config/hibernate.properties</value>
          </list>
          </property>
          </bean>
          <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
          destroy-method="close">
          <property name="driverClass" value="$

          {database.working.driver}

          "></property>
          <property name="jdbcUrl" value="$

          {database.working.url}

          "></property>
          <property name="user" value="$

          {database.working.user}

          "></property>
          <property name="password" value="$

          {database.working.password}

          "></property>

          <property name="maxPoolSize" value="$

          {database.working.poolsize}

          "></property>
          <property name="minPoolSize" value="1"></property>
          <property name="initialPoolSize" value="1"></property>
          <property name="maxIdleTime" value="20"></property>
          </bean>
          <bean id="sessionFactory"
          class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
          <property name="dataSource" ref="dataSource" />
          <property name="packagesToScan">
          <list>
          <value>.*.model</value>
          </list>
          </property>
          <property name="hibernateProperties">
          <props>
          <prop key="hibernate.dialect">$

          {hibernate.dialect}

          </prop>
          <prop key="hibernate.show_sql">$

          {hibernate.show_sql}

          </prop>
          <prop key="hibernate.hbm2ddl.auto">none</prop>
          </props>
          </property>
          </bean>

          <bean id="transactionManager"
          class="org.springframework.orm.hibernate3.HibernateTransactionManager">
          <property name="sessionFactory" ref="sessionFactory"></property>
          </bean>
          <tx:annotation-driven transaction-manager="transactionManager" />
          </beans>

          struts config file: struts.xml

          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE struts PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
          "http://struts.apache.org/dtds/struts-2.3.dtd">
          <struts>
          <!-- <constant name="struts.objectFactory" value="spring" /> -->
          <constant name="struts.objectFactory" value="org.apache.struts2.spring.StrutsSpringObjectFactory" />
          <constant name="struts.devMode" value="false" />

          <package name="swordlite" namespace="/" extends="struts-default">
          <global-results>
          <result name="myerror">/mrg/error.jsp</result>
          <result name="re2Editpage">/mrg/re2Editpage.jsp</result>
          </global-results>
          <global-exception-mappings>
          <exception-mapping result="re2Editpage" exception="org.hibernate.PropertyValueException"></exception-mapping>
          </global-exception-mappings>
          </package>
          </struts>

          Show
          zeroyet zhouyong added a comment - My action class has a annotation. It is org.springframework.transaction.annotation.Transactional. Action work good if it has not org.springframework.transaction.annotation.Transactional AtestAction.java: package demo.action; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.ParentPackage; import org.apache.struts2.convention.annotation.Result; import org.apache.struts2.convention.annotation.Results; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Transactional @ParentPackage(value="swordlite") @Service("AtestAction") @Scope(value = "prototype") @Results( { @Result(name = "test", location = "testb", type = "chain", params = { "defineId", "${_defineId}", "rp", "${_resultPage}"} ) }) public class AtestAction { @Action(value = "/testa") public String run() throws Exception { return "test"; } } BtestAction.java: import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.ParentPackage; import org.apache.struts2.convention.annotation.Result; import org.apache.struts2.convention.annotation.Results; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Transactional @ParentPackage(value="swordlite") @Service("BtestAction") @Scope(value="prototype") @Results({ @Result(name="ok", location="/ok.jsp", type="dispatcher"), }) public class BtestAction { @Action(value = "/testb") public String run() throws Exception { return "ok"; } } request: http://localhost:8080/test/testa.action raise error: java.lang.ClassCastException: demo.action.AtestAction cannot be cast to demo.action.BtestAction spring config file: applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns ="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd "> <context:component-scan base-package=" . .action, .**.spring" /> <context:annotation-config /> <aop:aspectj-autoproxy proxy-target-class="true"/> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>WEB-INF/config/db.properties</value> <value>WEB-INF/config/hibernate.properties</value> </list> </property> </bean> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="$ {database.working.driver} "></property> <property name="jdbcUrl" value="$ {database.working.url} "></property> <property name="user" value="$ {database.working.user} "></property> <property name="password" value="$ {database.working.password} "></property> <property name="maxPoolSize" value="$ {database.working.poolsize} "></property> <property name="minPoolSize" value="1"></property> <property name="initialPoolSize" value="1"></property> <property name="maxIdleTime" value="20"></property> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="packagesToScan"> <list> <value> . *.model</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">$ {hibernate.dialect} </prop> <prop key="hibernate.show_sql">$ {hibernate.show_sql} </prop> <prop key="hibernate.hbm2ddl.auto">none</prop> </props> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <tx:annotation-driven transaction-manager="transactionManager" /> </beans> struts config file: struts.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <!-- <constant name="struts.objectFactory" value="spring" /> --> <constant name="struts.objectFactory" value="org.apache.struts2.spring.StrutsSpringObjectFactory" /> <constant name="struts.devMode" value="false" /> <package name="swordlite" namespace="/" extends="struts-default"> <global-results> <result name="myerror">/mrg/error.jsp</result> <result name="re2Editpage">/mrg/re2Editpage.jsp</result> </global-results> <global-exception-mappings> <exception-mapping result="re2Editpage" exception="org.hibernate.PropertyValueException"></exception-mapping> </global-exception-mappings> </package> </struts>
          Hide
          lukaszlenart Lukasz Lenart added a comment -

          Could you wrap your code snippets with {code:xml} or with {noformat}?

          Show
          lukaszlenart Lukasz Lenart added a comment - Could you wrap your code snippets with {code:xml} or with {noformat}?
          Hide
          zeroyet zhouyong added a comment -

          eclipse web application

          Show
          zeroyet zhouyong added a comment - eclipse web application
          Hide
          zeroyet zhouyong added a comment -

          I have attached file : "test.zip"

          Show
          zeroyet zhouyong added a comment - I have attached file : "test.zip"
          Hide
          zeroyet zhouyong added a comment -

          pleas use 7z to unzip

          Show
          zeroyet zhouyong added a comment - pleas use 7z to unzip
          Hide
          zeroyet zhouyong added a comment -

          In struts 2.2.1, no error

          Show
          zeroyet zhouyong added a comment - In struts 2.2.1, no error
          Hide
          maurizio.cucchiara Maurizio Cucchiara added a comment -

          I'm pretty sure it's something related with AOP and AspectJ.

          zhouyong, again, can you post the whole stacktrace?

          Show
          maurizio.cucchiara Maurizio Cucchiara added a comment - I'm pretty sure it's something related with AOP and AspectJ. zhouyong , again, can you post the whole stacktrace?
          Hide
          zeroyet zhouyong added a comment - - edited

          stacktrace is added

          Show
          zeroyet zhouyong added a comment - - edited stacktrace is added
          Hide
          lukaszlenart Lukasz Lenart added a comment -

          Maybe it is related to WW-3488 - could you check with version 2.2.2 as well?

          Show
          lukaszlenart Lukasz Lenart added a comment - Maybe it is related to WW-3488 - could you check with version 2.2.2 as well?
          Hide
          zeroyet zhouyong added a comment -
          Show
          zeroyet zhouyong added a comment - I don't found 2.2.2 at http://archive.apache.org/dist/struts/binaries/
          Hide
          lukaszlenart Lukasz Lenart added a comment -

          My mistake, please try with 2.2.3

          Show
          lukaszlenart Lukasz Lenart added a comment - My mistake, please try with 2.2.3
          Hide
          zeroyet zhouyong added a comment -

          2.2.3 has same error like 2.3.x. The code of ChainingInterceptor.intercept (2.2.3) is same to 2.3.x

          Show
          zeroyet zhouyong added a comment - 2.2.3 has same error like 2.3.x. The code of ChainingInterceptor.intercept (2.2.3) is same to 2.3.x
          Hide
          yasser.zamani Yasser Zamani added a comment -

          I could reproduce it in a working maven project which I attached!
          I'm working on it.
          Thanks for your report, zhouyong!

          Show
          yasser.zamani Yasser Zamani added a comment - I could reproduce it in a working maven project which I attached! I'm working on it. Thanks for your report, zhouyong !
          Hide
          yasser.zamani Yasser Zamani added a comment -

          Oh...there is a serious problem with ChainingInterceptor! It copies all properties of Spring proxied objects of actions which breaks down Spring advisors, callbacks and etc.

          I attached my proposal solution where it's ChainingInterceptor copies only those properties which are originally defined by user before any ObjectFactory like Spring change or add to them.

          I hope it helps even as an inspiration

          Show
          yasser.zamani Yasser Zamani added a comment - Oh...there is a serious problem with ChainingInterceptor ! It copies all properties of Spring proxied objects of actions which breaks down Spring advisors, callbacks and etc. I attached my proposal solution where it's ChainingInterceptor copies only those properties which are originally defined by user before any ObjectFactory like Spring change or add to them. I hope it helps even as an inspiration
          Hide
          lukaszlenart Lukasz Lenart added a comment -

          Thanks Yasser Zamani - it's a good candidate for 2.5 version

          Show
          lukaszlenart Lukasz Lenart added a comment - Thanks Yasser Zamani - it's a good candidate for 2.5 version
          Hide
          yasser.zamani Yasser Zamani added a comment -

          Lukasz Lenart, the problem exists even with latest Spring and Struts2. I reviewed my previous years attached patch and today, I found I can fix this better i.e. not using includes which is for user usage but using an internal change to pass the original object to reflectionProvider.copy in ChainingInterceptor instead of proxied object.

          I will be working on it.

          Show
          yasser.zamani Yasser Zamani added a comment - Lukasz Lenart , the problem exists even with latest Spring and Struts2. I reviewed my previous years attached patch and today, I found I can fix this better i.e. not using includes which is for user usage but using an internal change to pass the original object to reflectionProvider.copy in ChainingInterceptor instead of proxied object. I will be working on it.
          Hide
          githubbot ASF GitHub Bot added a comment -

          GitHub user yasserzamani opened a pull request:

          https://github.com/apache/struts/pull/118

          WW-4105 OgnlUtil improved in order to only setting properties defined

          With these changes, [OgnlUtil](https://github.com/apache/struts/blob/master/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java) can set only properties defined in the given "editable" class (or interface) which can be used e.g. in chaining interceptor to skip proxy properties of proxied chained actions, that avoid breaking upper level technologies like Spring Proxying.

          You can merge this pull request into a Git repository by running:

          $ git pull https://github.com/yasserzamani/struts WW-4105

          Alternatively you can review and apply these changes as the patch at:

          https://github.com/apache/struts/pull/118.patch

          To close this pull request, make a commit to your master/trunk branch
          with (at least) the following in the commit message:

          This closes #118


          commit 6e7a14784c906f2cb6c638bef25e610459aa8f6f
          Author: Yasser Zamani <yasser.zamani@live.com>
          Date: 2017-02-12T11:11:21Z

          WW-4105 OgnlUtil improved in order to only setting properties defined
          in the given "editable" class (or interface)


          Show
          githubbot ASF GitHub Bot added a comment - GitHub user yasserzamani opened a pull request: https://github.com/apache/struts/pull/118 WW-4105 OgnlUtil improved in order to only setting properties defined With these changes, [OgnlUtil] ( https://github.com/apache/struts/blob/master/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java ) can set only properties defined in the given "editable" class (or interface) which can be used e.g. in chaining interceptor to skip proxy properties of proxied chained actions, that avoid breaking upper level technologies like Spring Proxying. You can merge this pull request into a Git repository by running: $ git pull https://github.com/yasserzamani/struts WW-4105 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/struts/pull/118.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #118 commit 6e7a14784c906f2cb6c638bef25e610459aa8f6f Author: Yasser Zamani <yasser.zamani@live.com> Date: 2017-02-12T11:11:21Z WW-4105 OgnlUtil improved in order to only setting properties defined in the given "editable" class (or interface)
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user lukaszlenart commented on a diff in the pull request:

          https://github.com/apache/struts/pull/118#discussion_r100772955

          — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java —
          @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) {
          Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
          for (Object object : list) {
          if (shouldCopy(object)) {

          • reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes);
            + String actionConfigClassName = invocation.getProxy().getConfig().getClassName();
            + Object action = invocation.getAction();
            + if (action.getClass().getName().equals(actionConfigClassName))
            + reflectionProvider.copy(object, action, ctxMap, prepareExcludes(), includes, null);
            + else { //only setting properties defined in the given config class e.g. to skip proxy properties (WW-4105)
            + Class <?> editable;
            + try { + editable = Class.forName(actionConfigClassName); + }

            catch (ClassNotFoundException e) {
            + LOG.warn("An unexpected state. This may be due to a bug. Please report this: ClassNotFoundException" + actionConfigClassName);

              • End diff –

          What about logging exception here as well?

          Show
          githubbot ASF GitHub Bot added a comment - Github user lukaszlenart commented on a diff in the pull request: https://github.com/apache/struts/pull/118#discussion_r100772955 — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java — @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) { Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); for (Object object : list) { if (shouldCopy(object)) { reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes); + String actionConfigClassName = invocation.getProxy().getConfig().getClassName(); + Object action = invocation.getAction(); + if (action.getClass().getName().equals(actionConfigClassName)) + reflectionProvider.copy(object, action, ctxMap, prepareExcludes(), includes, null); + else { //only setting properties defined in the given config class e.g. to skip proxy properties ( WW-4105 ) + Class <?> editable; + try { + editable = Class.forName(actionConfigClassName); + } catch (ClassNotFoundException e) { + LOG.warn("An unexpected state. This may be due to a bug. Please report this: ClassNotFoundException" + actionConfigClassName); End diff – What about logging exception here as well?
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on a diff in the pull request:

          https://github.com/apache/struts/pull/118#discussion_r100774158

          — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java —
          @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) {
          Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
          for (Object object : list) {
          if (shouldCopy(object)) {

          • reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes);
            + String actionConfigClassName = invocation.getProxy().getConfig().getClassName();
            + Object action = invocation.getAction();
            + if (action.getClass().getName().equals(actionConfigClassName))
            + reflectionProvider.copy(object, action, ctxMap, prepareExcludes(), includes, null);
            + else { //only setting properties defined in the given config class e.g. to skip proxy properties (WW-4105)
            + Class <?> editable;
            + try { + editable = Class.forName(actionConfigClassName); + }

            catch (ClassNotFoundException e) {
            + LOG.warn("An unexpected state. This may be due to a bug. Please report this: ClassNotFoundException" + actionConfigClassName);

              • End diff –

          It's better, thank you! done and committed.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on a diff in the pull request: https://github.com/apache/struts/pull/118#discussion_r100774158 — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java — @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) { Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); for (Object object : list) { if (shouldCopy(object)) { reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes); + String actionConfigClassName = invocation.getProxy().getConfig().getClassName(); + Object action = invocation.getAction(); + if (action.getClass().getName().equals(actionConfigClassName)) + reflectionProvider.copy(object, action, ctxMap, prepareExcludes(), includes, null); + else { //only setting properties defined in the given config class e.g. to skip proxy properties ( WW-4105 ) + Class <?> editable; + try { + editable = Class.forName(actionConfigClassName); + } catch (ClassNotFoundException e) { + LOG.warn("An unexpected state. This may be due to a bug. Please report this: ClassNotFoundException" + actionConfigClassName); End diff – It's better, thank you! done and committed.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on a diff in the pull request:

          https://github.com/apache/struts/pull/118#discussion_r100774641

          — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java —
          @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) {
          Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
          for (Object object : list) {
          if (shouldCopy(object)) {

          • reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes);
            + String actionConfigClassName = invocation.getProxy().getConfig().getClassName();
            + Object action = invocation.getAction();
            + if (action.getClass().getName().equals(actionConfigClassName))
            + reflectionProvider.copy(object, action, ctxMap, prepareExcludes(), includes, null);
            + else { //only setting properties defined in the given config class e.g. to skip proxy properties (WW-4105)
            + Class <?> editable;
            + try { + editable = Class.forName(actionConfigClassName); + }

            catch (ClassNotFoundException e) {
            + LOG.warn("An unexpected state. This may be due to a bug. Please report this: ClassNotFoundException" + actionConfigClassName);

              • End diff –

          I also fixed Indentations to use 4 spaces instead of tab, both in my current PRs and my eclipse. Sorry, I'll be more careful about formatting in my next works

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on a diff in the pull request: https://github.com/apache/struts/pull/118#discussion_r100774641 — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java — @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) { Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); for (Object object : list) { if (shouldCopy(object)) { reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes); + String actionConfigClassName = invocation.getProxy().getConfig().getClassName(); + Object action = invocation.getAction(); + if (action.getClass().getName().equals(actionConfigClassName)) + reflectionProvider.copy(object, action, ctxMap, prepareExcludes(), includes, null); + else { //only setting properties defined in the given config class e.g. to skip proxy properties ( WW-4105 ) + Class <?> editable; + try { + editable = Class.forName(actionConfigClassName); + } catch (ClassNotFoundException e) { + LOG.warn("An unexpected state. This may be due to a bug. Please report this: ClassNotFoundException" + actionConfigClassName); End diff – I also fixed Indentations to use 4 spaces instead of tab, both in my current PRs and my eclipse. Sorry, I'll be more careful about formatting in my next works
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on a diff in the pull request:

          https://github.com/apache/struts/pull/118#discussion_r100990118

          — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java —
          @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) {
          Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
          for (Object object : list) {
          if (shouldCopy(object)) {

          • reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes);
            + String actionConfigClassName = invocation.getProxy().getConfig().getClassName();
              • End diff –

          Please wait and do not merge until I check if getConfig and getClassName are always ready and are as expected e.g. when using convention or spring plugin!

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on a diff in the pull request: https://github.com/apache/struts/pull/118#discussion_r100990118 — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java — @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) { Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); for (Object object : list) { if (shouldCopy(object)) { reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes); + String actionConfigClassName = invocation.getProxy().getConfig().getClassName(); End diff – Please wait and do not merge until I check if getConfig and getClassName are always ready and are as expected e.g. when using convention or spring plugin!
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on a diff in the pull request:

          https://github.com/apache/struts/pull/118#discussion_r100990614

          — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java —
          @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) {
          Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
          for (Object object : list) {
          if (shouldCopy(object)) {

          • reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes);
            + String actionConfigClassName = invocation.getProxy().getConfig().getClassName();
              • End diff –

          Please wait and do not merge! until I check if `getConfig` and `getClassName` are always ready and are as expected e.g. when using convention or spring plugin!

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on a diff in the pull request: https://github.com/apache/struts/pull/118#discussion_r100990614 — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java — @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) { Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); for (Object object : list) { if (shouldCopy(object)) { reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes); + String actionConfigClassName = invocation.getProxy().getConfig().getClassName(); End diff – Please wait and do not merge! until I check if `getConfig` and `getClassName` are always ready and are as expected e.g. when using convention or spring plugin!
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user lukaszlenart commented on the issue:

          https://github.com/apache/struts/pull/118

          @yasserzamani you should be able to mark this PR with a label `Ready for merge`

          Show
          githubbot ASF GitHub Bot added a comment - Github user lukaszlenart commented on the issue: https://github.com/apache/struts/pull/118 @yasserzamani you should be able to mark this PR with a label `Ready for merge`
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on a diff in the pull request:

          https://github.com/apache/struts/pull/118#discussion_r101103182

          — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java —
          @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) {
          Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
          for (Object object : list) {
          if (shouldCopy(object)) {

          • reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes);
            + String actionConfigClassName = invocation.getProxy().getConfig().getClassName();
              • End diff –

          As I guessed, this line does not work when action is a spring bean (`getClassName` returns the spring bean id, not fully qualified name of class).

          Fortunately it works with actions created by convention plugin.

          I will be working on it by checking all references which set or get class name. I also will add some unit tests to check if similar issues occurs in future.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on a diff in the pull request: https://github.com/apache/struts/pull/118#discussion_r101103182 — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java — @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) { Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); for (Object object : list) { if (shouldCopy(object)) { reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes); + String actionConfigClassName = invocation.getProxy().getConfig().getClassName(); End diff – As I guessed, this line does not work when action is a spring bean (`getClassName` returns the spring bean id, not fully qualified name of class). Fortunately it works with actions created by convention plugin. I will be working on it by checking all references which set or get class name. I also will add some unit tests to check if similar issues occurs in future.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on a diff in the pull request:

          https://github.com/apache/struts/pull/118#discussion_r101285251

          — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java —
          @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) {
          Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
          for (Object object : list) {
          if (shouldCopy(object)) {

          • reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes);
            + String actionConfigClassName = invocation.getProxy().getConfig().getClassName();
              • End diff –

          @lukaszlenart , I study a lot but, while user can equip any custom `ObjectFactory` to create actions (here user has many options like spring aop, javassist, jdk, cglib or any other library), it seems there is no way to determine which properties to set and which should be skipped *except asking from user itself*.

          While there are `includes` and `excludes` available for user, but for save user from a lot of typing and also more readability, *what do you think about featuring a new optional parameter named `editableClass` like below?*
          ```xml
          <result type="chain">
          <param name="actionName">myOriginalAction</param>
          <param name="editableClass">me.myname.myactions.MyOriginalAction</param>
          </result>
          ```
          or
          ```xml
          <interceptor-ref name="chainStack">
          <param name="chain.editableClass">me.myname.myactions.MyOriginalAction</param>
          </interceptor-ref>
          ```
          After this featuring, rest of codes of this PR will work and fixes issue in a clean gracefully way.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on a diff in the pull request: https://github.com/apache/struts/pull/118#discussion_r101285251 — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java — @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) { Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); for (Object object : list) { if (shouldCopy(object)) { reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes); + String actionConfigClassName = invocation.getProxy().getConfig().getClassName(); End diff – @lukaszlenart , I study a lot but, while user can equip any custom `ObjectFactory` to create actions (here user has many options like spring aop, javassist, jdk, cglib or any other library), it seems there is no way to determine which properties to set and which should be skipped * except asking from user itself *. While there are `includes` and `excludes` available for user, but for save user from a lot of typing and also more readability, * what do you think about featuring a new optional parameter named `editableClass` like below? * ```xml <result type="chain"> <param name="actionName">myOriginalAction</param> <param name="editableClass">me.myname.myactions.MyOriginalAction</param> </result> ``` or ```xml <interceptor-ref name="chainStack"> <param name="chain.editableClass">me.myname.myactions.MyOriginalAction</param> </interceptor-ref> ``` After this featuring, rest of codes of this PR will work and fixes issue in a clean gracefully way.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user lukaszlenart commented on a diff in the pull request:

          https://github.com/apache/struts/pull/118#discussion_r101292894

          — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java —
          @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) {
          Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
          for (Object object : list) {
          if (shouldCopy(object)) {

          • reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes);
            + String actionConfigClassName = invocation.getProxy().getConfig().getClassName();
              • End diff –

          What `editableClass` means here? Shouldn't it be a `originClass` or `targetClass`?

          Show
          githubbot ASF GitHub Bot added a comment - Github user lukaszlenart commented on a diff in the pull request: https://github.com/apache/struts/pull/118#discussion_r101292894 — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java — @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) { Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); for (Object object : list) { if (shouldCopy(object)) { reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes); + String actionConfigClassName = invocation.getProxy().getConfig().getClassName(); End diff – What `editableClass` means here? Shouldn't it be a `originClass` or `targetClass`?
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on a diff in the pull request:

          https://github.com/apache/struts/pull/118#discussion_r101302678

          — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java —
          @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) {
          Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
          for (Object object : list) {
          if (shouldCopy(object)) {

          • reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes);
            + String actionConfigClassName = invocation.getProxy().getConfig().getClassName();
              • End diff –

          > editable - the class (or interface) to restrict property setting to i.e. only setting properties defined in the given "editable" class (or interface))
          I learnt this name from Spring docs. User also can set a class or interface which is not source class nor target class but an encapsulation of desired properties inside it.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on a diff in the pull request: https://github.com/apache/struts/pull/118#discussion_r101302678 — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java — @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) { Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); for (Object object : list) { if (shouldCopy(object)) { reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes); + String actionConfigClassName = invocation.getProxy().getConfig().getClassName(); End diff – > editable - the class (or interface) to restrict property setting to i.e. only setting properties defined in the given "editable" class (or interface)) I learnt this name from Spring docs. User also can set a class or interface which is not source class nor target class but an encapsulation of desired properties inside it.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user lukaszlenart commented on a diff in the pull request:

          https://github.com/apache/struts/pull/118#discussion_r101308839

          — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java —
          @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) {
          Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
          for (Object object : list) {
          if (shouldCopy(object)) {

          • reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes);
            + String actionConfigClassName = invocation.getProxy().getConfig().getClassName();
              • End diff –

          Hm... ok, let's do it

          Show
          githubbot ASF GitHub Bot added a comment - Github user lukaszlenart commented on a diff in the pull request: https://github.com/apache/struts/pull/118#discussion_r101308839 — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java — @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) { Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); for (Object object : list) { if (shouldCopy(object)) { reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes); + String actionConfigClassName = invocation.getProxy().getConfig().getClassName(); End diff – Hm... ok, let's do it
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on a diff in the pull request:

          https://github.com/apache/struts/pull/118#discussion_r101312503

          — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java —
          @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) {
          Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
          for (Object object : list) {
          if (shouldCopy(object)) {

          • reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes);
            + String actionConfigClassName = invocation.getProxy().getConfig().getClassName();
              • End diff –

          thank you :heart_eyes:

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on a diff in the pull request: https://github.com/apache/struts/pull/118#discussion_r101312503 — Diff: core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java — @@ -160,7 +160,20 @@ private void copyStack(ActionInvocation invocation, CompoundRoot root) { Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); for (Object object : list) { if (shouldCopy(object)) { reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes); + String actionConfigClassName = invocation.getProxy().getConfig().getClassName(); End diff – thank you :heart_eyes:
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/118

          😍 PR re-based with last master and ChainingInterceptor equipped with an optional param (editableClass) which user can set to a custom class (or interface) fully qualified name to restrict property setting like below:
          ```xml
          <interceptor-ref name="chainStack">
          <param name="chain.editableClass">me.myname.myactions.MyClassOrInterface</param>
          </interceptor-ref>
          ```
          It is useful when chained actions are unknown proxies created by an unknown object factory and we do not want to copy upper level proxy information which usually breaks their functionality 👌

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/118 😍 PR re-based with last master and ChainingInterceptor equipped with an optional param (editableClass) which user can set to a custom class (or interface) fully qualified name to restrict property setting like below: ```xml <interceptor-ref name="chainStack"> <param name="chain.editableClass">me.myname.myactions.MyClassOrInterface</param> </interceptor-ref> ``` It is useful when chained actions are unknown proxies created by an unknown object factory and we do not want to copy upper level proxy information which usually breaks their functionality 👌
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/118

          @lukaszlenart , I am not able to mark this PR with a label `Ready for merge`. I think because I should not have write access to this repository.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/118 @lukaszlenart , I am not able to mark this PR with a label `Ready for merge`. I think because I should not have write access to this repository.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user lukaszlenart commented on the issue:

          https://github.com/apache/struts/pull/118

          ech... will ask Infra

          Show
          githubbot ASF GitHub Bot added a comment - Github user lukaszlenart commented on the issue: https://github.com/apache/struts/pull/118 ech... will ask Infra
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user lukaszlenart commented on the issue:

          https://github.com/apache/struts/pull/118

          only someone with write access can do it, so let's assume that adding :+1: by the author means `Ready for merge` - I will update docs

          Show
          githubbot ASF GitHub Bot added a comment - Github user lukaszlenart commented on the issue: https://github.com/apache/struts/pull/118 only someone with write access can do it, so let's assume that adding :+1: by the author means `Ready for merge` - I will update docs
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/118

          I improved this PR with an interesting Unit Test which prevents similar issues occurrence in future i.e. it checks if `chaining Spring AOPed actions` always works. This Unit Test reproduce the problem and fails in current code which verify the issue WW-4105 existence.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/118 I improved this PR with an interesting Unit Test which prevents similar issues occurrence in future i.e. it checks if `chaining Spring AOPed actions` always works. This Unit Test reproduce the problem and fails in current code which verify the issue WW-4105 existence.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/118

          @lukaszlenart , this could be postponed to resolution of WW-4751(https://issues.apache.org/jira/browse/WW-4751).

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/118 @lukaszlenart , this could be postponed to resolution of WW-4751 ( https://issues.apache.org/jira/browse/WW-4751 ).
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user lukaszlenart commented on the issue:

          https://github.com/apache/struts/pull/118

          Sure, feel free to implement that

          Show
          githubbot ASF GitHub Bot added a comment - Github user lukaszlenart commented on the issue: https://github.com/apache/struts/pull/118 Sure, feel free to implement that
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/118

          @lukaszlenart , I love to implement that but as changes may occur in several places from Core to Plugins e.g. JSONResult, I decided to get your agreement and confirmation if you also agree that Struts2 needs this improvement. Likely everywhere Struts2 works with Action's fields, we will need a change. If you agree, I can start carefuly improve there 👌 thank you for your confidence.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/118 @lukaszlenart , I love to implement that but as changes may occur in several places from Core to Plugins e.g. JSONResult, I decided to get your agreement and confirmation if you also agree that Struts2 needs this improvement. Likely everywhere Struts2 works with Action's fields, we will need a change. If you agree, I can start carefuly improve there 👌 thank you for your confidence.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/118

          @lukaszlenart , another thing where I need your recommendation is, after this improvement, all users have to convert from
          ```xml
          <action name="myAction" class="myBeanName">
          ```
          to
          ```xml
          <action name="myAction" class="mypackage.MyAction" bean="myBeanName">
          ```
          in their existing projects which worries me. 😢 What do you do in such changes? thank you.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/118 @lukaszlenart , another thing where I need your recommendation is, after this improvement, all users have to convert from ```xml <action name="myAction" class="myBeanName"> ``` to ```xml <action name="myAction" class="mypackage.MyAction" bean="myBeanName"> ``` in their existing projects which worries me. 😢 What do you do in such changes? thank you.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user lukaszlenart commented on the issue:

          https://github.com/apache/struts/pull/118

          Unacceptable ... what about annotations or conventions? Also it would be good to have the attribute `bean` optional.

          Show
          githubbot ASF GitHub Bot added a comment - Github user lukaszlenart commented on the issue: https://github.com/apache/struts/pull/118 Unacceptable ... what about annotations or conventions? Also it would be good to have the attribute `bean` optional.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/118

          @lukaszlenart , Yes, surely attribute `bean` is, will be and should be optional. Also there are no problem with actions which used attribute `class` as a class not a bean name. But unfortunately, Struts2 uses attribute `class` also for a bean name rather than a separate attribute which causes not backward compatible of this improvement

          About Annotations I know they works without any change. For conventions and wildcards and etc I should see.

          Anyway, in case of when action are beans inside user's object factory, we do not have any way except force user to change config and specify real class , Or add another optional attribute and add more conditional and not general codes for this improvement.

          What is your recommendation in such changes? thanks.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/118 @lukaszlenart , Yes, surely attribute `bean` is, will be and should be optional. Also there are no problem with actions which used attribute `class` as a class not a bean name. But unfortunately, Struts2 uses attribute `class` also for a bean name rather than a separate attribute which causes not backward compatible of this improvement About Annotations I know they works without any change. For conventions and wildcards and etc I should see. Anyway, in case of when action are beans inside user's object factory, we do not have any way except force user to change config and specify real class , Or add another optional attribute and add more conditional and not general codes for this improvement. What is your recommendation in such changes? thanks.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/118

          @lukaszlenart , thank you, so I will add only one attribute named `bean`. if specified, we use that improvement, elsewhere current behavior. i.e. we will keep old behavior but with some specific if-else statements rather than more clean and general codes. If you agree with this and my previous comment about several places changes, the please 👍 for confirmation then I start

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/118 @lukaszlenart , thank you, so I will add only one attribute named `bean`. if specified, we use that improvement, elsewhere current behavior. i.e. we will keep old behavior but with some specific if-else statements rather than more clean and general codes. If you agree with this and my previous comment about several places changes, the please 👍 for confirmation then I start
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user lukaszlenart commented on the issue:

          https://github.com/apache/struts/pull/118

          Sure, go ahead I know it would be better to have just one implementation but we can mark the old code as deprecated and remove it at some point.

          Show
          githubbot ASF GitHub Bot added a comment - Github user lukaszlenart commented on the issue: https://github.com/apache/struts/pull/118 Sure, go ahead I know it would be better to have just one implementation but we can mark the old code as deprecated and remove it at some point.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user aleksandr-m commented on the issue:

          https://github.com/apache/struts/pull/118

          @yasserzamani in case of when action are beans inside user's object factory, we do not have any way except force user to change config and specify real class

          Can you elaborate? It really looks weird to specify both bean and the class name.

          Show
          githubbot ASF GitHub Bot added a comment - Github user aleksandr-m commented on the issue: https://github.com/apache/struts/pull/118 @yasserzamani in case of when action are beans inside user's object factory, we do not have any way except force user to change config and specify real class Can you elaborate? It really looks weird to specify both bean and the class name.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/118

          @aleksandr-m , as an example, consider when action proxified with another technology like Spring and the user assumes that Struts2 only operates in it's borders, but currently, Struts2 does not know his borders about the action object e.g. it copies proxy information like advices when it chains actions, it generates json data from them in JSONResult, it copies ActionSupport's data when it chains which forced us to declare includes/excludes, In a security point of view, someone may successfully change proxy information of the action by an HTTP request with named parameters!

          All of these can be avoided if Struts2 know user desired config time class of the action. Struts2 knows this except when user gives actions up to any object factory like Spring or any other custom object factory. in such situation, Stuts2 looses information about config time class name of the action. yes, Struts2 has the object, but there is no any clean way to check if it's a proxy and unwrap it to target class!

          So, by attribute `bean`, the user specifies object, and by attribute `class`, specifies Struts2's borders i.e. Struts2 will exclude all subclasses above `class` and all superclasses under and including ActionSupport. I defined these as an improvement at WW-4751(https://issues.apache.org/jira/browse/WW-4751).

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/118 @aleksandr-m , as an example, consider when action proxified with another technology like Spring and the user assumes that Struts2 only operates in it's borders, but currently, Struts2 does not know his borders about the action object e.g. it copies proxy information like advices when it chains actions, it generates json data from them in JSONResult, it copies ActionSupport's data when it chains which forced us to declare includes/excludes, In a security point of view, someone may successfully change proxy information of the action by an HTTP request with named parameters! All of these can be avoided if Struts2 know user desired config time class of the action . Struts2 knows this except when user gives actions up to any object factory like Spring or any other custom object factory. in such situation, Stuts2 looses information about config time class name of the action. yes, Struts2 has the object, but there is no any clean way to check if it's a proxy and unwrap it to target class! So, by attribute `bean`, the user specifies object, and by attribute `class`, specifies Struts2's borders i.e. Struts2 will exclude all subclasses above `class` and all superclasses under and including ActionSupport. I defined these as an improvement at WW-4751 ( https://issues.apache.org/jira/browse/WW-4751 ).
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user aleksandr-m commented on the issue:

          https://github.com/apache/struts/pull/118

          Let's break it down:

          *chain*
          First of all using `chain` is discouraged. Proxying the action itself is not the best practice too.

          If the only viable solution to know target class is to declare a real class of the bean then it should be done in the chain interceptor not in the action configuration.

          *json result*
          What is the problem with generating proxy data into json? What if this is what is really needed?

          *excluding `ActionSupport`*
          If `ActionSupport` is excluded then its methods cannot be used in the JSP (e.g. `getText`). In case of `chain` action errors / messages won't be moved to the next action. Etc.

          *overall*
          someone may successfully change proxy information of the action by an HTTP request with named parameters
          Are you sure? Can you provide some example?

          there is no any clean way to check if it's a proxy and unwrap it to target class
          How knowing the name of the real class helps in that case? What are you going to do with it?
          If it is spring proxy then there are helper methods to get target class from the instance (e.g. `AopUtils`). If there is no clean way to do this in the Struts core utility class then it can be delegated to current object factory.

          Show
          githubbot ASF GitHub Bot added a comment - Github user aleksandr-m commented on the issue: https://github.com/apache/struts/pull/118 Let's break it down: * chain * First of all using `chain` is discouraged. Proxying the action itself is not the best practice too. If the only viable solution to know target class is to declare a real class of the bean then it should be done in the chain interceptor not in the action configuration. * json result * What is the problem with generating proxy data into json? What if this is what is really needed? * excluding `ActionSupport` * If `ActionSupport` is excluded then its methods cannot be used in the JSP (e.g. `getText`). In case of `chain` action errors / messages won't be moved to the next action. Etc. * overall * someone may successfully change proxy information of the action by an HTTP request with named parameters Are you sure? Can you provide some example? there is no any clean way to check if it's a proxy and unwrap it to target class How knowing the name of the real class helps in that case? What are you going to do with it? If it is spring proxy then there are helper methods to get target class from the instance (e.g. `AopUtils`). If there is no clean way to do this in the Struts core utility class then it can be delegated to current object factory.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/118

          @lukaszlenart , @aleksandr-m , thank you for your comments. Today I did not have enough time to prepare more dangerous security issue example but until I prepare one in comming days, please consider the following example:

          Simply, I created an action with json result and with Spring's Transactional annotation (please consider that I know transactional actions are not good practice but it's an example, the Struts2 user may use any unknown 3rd party annotation *assuming Struts2 only operates in his borders rather than overlapping other technologies like Spring*, the user may not get any exception or error and so, may not check the generated json, but Struts2 emits also his objects information to hackers by json result).

          OK, this is the result of http://localhost:7780/springAction1
          ```json
          {
          "advisors":[
          {
          "advice":{
          "transactionAttributeSource":{

          },
          "transactionManager":null
          },
          "adviceBeanName":"org.springframework.transaction.interceptor.TransactionInterceptor#0",
          "order":2147483647,
          "perInstance":true,
          "pointcut":{
          "classFilter":{

          },
          "methodMatcher":null,
          "runtime":false
          }
          }
          ],
          "callbacks":[ { }, { }, { }, { }, { }, { }, { }
          ],
          "exposeProxy":false,
          "frozen":false,
          "preFiltered":true,
          "proxiedInterfaces":[

          ],
          "proxyTargetClass":true,
          "targetClass":"class me.zamani.yasser.ww_convention.springactions.springAction1",
          "targetSource":{
          "static":true,
          "target":{

          },
          "targetClass":"class me.zamani.yasser.ww_convention.springactions.springAction1"
          }
          }
          ```

          And this is the result of http://localhost:7780/springAction1?advisors[0].adviceBeanName=&advisors[0].order=-1&exposeProxy=true&preFiltered=false
          ```json
          {
          "advisors":[
          {
          "advice":{
          "transactionAttributeSource":{

          },
          "transactionManager":null
          },
          "adviceBeanName":"",
          "order":-1,
          "perInstance":true,
          "pointcut":{
          "classFilter":{

          },
          "methodMatcher":null,
          "runtime":false
          }
          }
          ],
          "callbacks":[ { }, { }, { }, { }, { }, { }, { }
          ],
          "exposeProxy":true,
          "frozen":false,
          "preFiltered":false,
          "proxiedInterfaces":[

          ],
          "proxyTargetClass":true,
          "targetClass":"class me.zamani.yasser.ww_convention.springactions.springAction1",
          "targetSource":{
          "static":true,
          "target":{

          },
          "targetClass":"class me.zamani.yasser.ww_convention.springactions.springAction1"
          }
          }
          ```

          As you see, I changed something and then if I re-get even without any query string, these changes are persistence :\

          Furthermore, json result on Spring AOPed actions simply fails with:
          ```
          org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: java.lang.IllegalAccessException: Class org.apache.struts2.json.JSONWriter can not access a member of class org.springframework.aop.TruePointcut with modifiers "public"
          at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:269)
          at org.apache.struts2.json.JSONWriter.processCustom(JSONWriter.java:197)
          at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:182)
          at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:143)
          at org.apache.struts2.json.JSONWriter.write(JSONWriter.java:110)
          at org.apache.struts2.json.JSONUtil.serialize(JSONUtil.java:194)
          at org.apache.struts2.json.JSONResult.createJSONString(JSONResult.java:222)
          at org.apache.struts2.json.JSONResult.execute(JSONResult.java:196)
          at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:373)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:277)
          at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:253)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:177)
          at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:260)
          at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:73)
          at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.doIntercept(ConversionErrorInterceptor.java:139)
          at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:133)
          at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:133)
          at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:192)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:69)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at org.apache.struts2.interceptor.DateTextFieldInterceptor.intercept(DateTextFieldInterceptor.java:115)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:88)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:246)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:99)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:139)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:156)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:174)
          at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at org.apache.struts2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:122)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:171)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:195)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:193)
          at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
          at org.apache.struts2.factory.StrutsActionProxy.execute(StrutsActionProxy.java:54)
          at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:564)
          at org.apache.struts2.dispatcher.ExecuteOperations.executeAction(ExecuteOperations.java:81)
          at org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:143)
          at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
          at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
          at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
          at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
          at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
          at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
          at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
          at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
          at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
          at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
          at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
          at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
          at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2430)
          at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2419)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
          at java.lang.Thread.run(Thread.java:745)
          Caused by: org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: java.lang.IllegalAccessException: Class org.apache.struts2.json.JSONWriter can not access a member of class org.springframework.aop.TruePointcut with modifiers "public"
          at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:269)
          at org.apache.struts2.json.JSONWriter.processCustom(JSONWriter.java:197)
          at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:182)
          at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:143)
          at org.apache.struts2.json.JSONWriter.array(JSONWriter.java:550)
          at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:170)
          at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:143)
          at org.apache.struts2.json.JSONWriter.add(JSONWriter.java:428)
          at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:254)
          ... 75 more
          Caused by: org.apache.struts2.json.JSONException: java.lang.IllegalAccessException: Class org.apache.struts2.json.JSONWriter can not access a member of class org.springframework.aop.TruePointcut with modifiers "public"
          at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:269)
          at org.apache.struts2.json.JSONWriter.processCustom(JSONWriter.java:197)
          at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:182)
          at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:143)
          at org.apache.struts2.json.JSONWriter.add(JSONWriter.java:428)
          at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:254)
          ... 83 more
          Caused by: java.lang.IllegalAccessException: Class org.apache.struts2.json.JSONWriter can not access a member of class org.springframework.aop.TruePointcut with modifiers "public"
          at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:109)
          at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:261)
          at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:253)
          at java.lang.reflect.Method.invoke(Method.java:599)
          at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:249)
          ... 88 more
          ```

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/118 @lukaszlenart , @aleksandr-m , thank you for your comments. Today I did not have enough time to prepare more dangerous security issue example but until I prepare one in comming days, please consider the following example: Simply, I created an action with json result and with Spring's Transactional annotation (please consider that I know transactional actions are not good practice but it's an example, the Struts2 user may use any unknown 3rd party annotation * assuming Struts2 only operates in his borders rather than overlapping other technologies like Spring *, the user may not get any exception or error and so, may not check the generated json, but Struts2 emits also his objects information to hackers by json result). OK, this is the result of http://localhost:7780/springAction1 ```json { "advisors":[ { "advice":{ "transactionAttributeSource":{ }, "transactionManager":null }, "adviceBeanName":"org.springframework.transaction.interceptor.TransactionInterceptor#0", "order":2147483647, "perInstance":true, "pointcut":{ "classFilter":{ }, "methodMatcher":null, "runtime":false } } ], "callbacks":[ { }, { }, { }, { }, { }, { }, { } ], "exposeProxy":false, "frozen":false, "preFiltered":true, "proxiedInterfaces":[ ], "proxyTargetClass":true, "targetClass":"class me.zamani.yasser.ww_convention.springactions.springAction1", "targetSource":{ "static":true, "target":{ }, "targetClass":"class me.zamani.yasser.ww_convention.springactions.springAction1" } } ``` And this is the result of http://localhost:7780/springAction1?advisors[0].adviceBeanName=&advisors[0].order=-1&exposeProxy=true&preFiltered=false ```json { "advisors":[ { "advice":{ "transactionAttributeSource":{ }, "transactionManager":null }, "adviceBeanName":"", "order":-1, "perInstance":true, "pointcut":{ "classFilter":{ }, "methodMatcher":null, "runtime":false } } ], "callbacks":[ { }, { }, { }, { }, { }, { }, { } ], "exposeProxy":true, "frozen":false, "preFiltered":false, "proxiedInterfaces":[ ], "proxyTargetClass":true, "targetClass":"class me.zamani.yasser.ww_convention.springactions.springAction1", "targetSource":{ "static":true, "target":{ }, "targetClass":"class me.zamani.yasser.ww_convention.springactions.springAction1" } } ``` As you see, I changed something and then if I re-get even without any query string, these changes are persistence :\ Furthermore, json result on Spring AOPed actions simply fails with: ``` org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: java.lang.IllegalAccessException: Class org.apache.struts2.json.JSONWriter can not access a member of class org.springframework.aop.TruePointcut with modifiers "public" at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:269) at org.apache.struts2.json.JSONWriter.processCustom(JSONWriter.java:197) at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:182) at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:143) at org.apache.struts2.json.JSONWriter.write(JSONWriter.java:110) at org.apache.struts2.json.JSONUtil.serialize(JSONUtil.java:194) at org.apache.struts2.json.JSONResult.createJSONString(JSONResult.java:222) at org.apache.struts2.json.JSONResult.execute(JSONResult.java:196) at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:373) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:277) at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:253) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:177) at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:260) at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:73) at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.doIntercept(ConversionErrorInterceptor.java:139) at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:133) at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:133) at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:192) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:69) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at org.apache.struts2.interceptor.DateTextFieldInterceptor.intercept(DateTextFieldInterceptor.java:115) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:88) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:246) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:99) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:139) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:156) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:174) at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at org.apache.struts2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:122) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:171) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:195) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:193) at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247) at org.apache.struts2.factory.StrutsActionProxy.execute(StrutsActionProxy.java:54) at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:564) at org.apache.struts2.dispatcher.ExecuteOperations.executeAction(ExecuteOperations.java:81) at org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:143) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603) at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2430) at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2419) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745) Caused by: org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: java.lang.IllegalAccessException: Class org.apache.struts2.json.JSONWriter can not access a member of class org.springframework.aop.TruePointcut with modifiers "public" at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:269) at org.apache.struts2.json.JSONWriter.processCustom(JSONWriter.java:197) at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:182) at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:143) at org.apache.struts2.json.JSONWriter.array(JSONWriter.java:550) at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:170) at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:143) at org.apache.struts2.json.JSONWriter.add(JSONWriter.java:428) at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:254) ... 75 more Caused by: org.apache.struts2.json.JSONException: java.lang.IllegalAccessException: Class org.apache.struts2.json.JSONWriter can not access a member of class org.springframework.aop.TruePointcut with modifiers "public" at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:269) at org.apache.struts2.json.JSONWriter.processCustom(JSONWriter.java:197) at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:182) at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:143) at org.apache.struts2.json.JSONWriter.add(JSONWriter.java:428) at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:254) ... 83 more Caused by: java.lang.IllegalAccessException: Class org.apache.struts2.json.JSONWriter can not access a member of class org.springframework.aop.TruePointcut with modifiers "public" at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:109) at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:261) at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:253) at java.lang.reflect.Method.invoke(Method.java:599) at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:249) ... 88 more ```
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/118

          @aleksandr-m , Thank you for your time and comments; please let me know what do you think about below; I would like to be sure about usefulness before starting implementation.

          > Are you sure? Can you provide some example?

          Yes, I created an attack example with latest Struts2 but I think I'm not allowed to post details here so I emailed to security@struts.apache.org because the example is really can be harmful and can be applied in an almost common usage by Struts2 users. *The vulnerability is because of operating Struts inside other technologies borders!*

          > How knowing the name of the real class helps in that case? What are you going to do with it?

          Knowing that helps Struts2 to not operate inside other technologies borders which may arise some vulnerability as mentioned above.

          > If it is spring proxy then there are helper methods to get target class from the instance (e.g. AopUtils). If there is no clean way to do this in the Struts core utility class then it can be delegated to current object factory.

          Struts2 dependency of Spring is optional e.g. AopUtils is not available in core. Furthermore, Struts2 user has several options for proxy creator from cglib, jdk to any unknown third party.

          > Proxying the action itself is not the best practice too.

          Please see [This is useful, for example, if you wish to apply more complex AOP or Spring-enabled technologies, such as Acegi](https://struts.apache.org/docs/spring-plugin.html).

          > What is the problem with generating proxy data into json? What if this is what is really needed?

          User may not get any exception then may not check the json result but actual result may help hackers. If this is what is really needed, then we can provide an option for user.

          > If ActionSupport is excluded then its methods cannot be used in the JSP (e.g. getText). In case of chain action errors / messages won't be moved to the next action. Etc.

          By word excluding, I meant in sensitive places rather than complete exclusion. In case of chain or any not sensitive place, we should think about solution

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/118 @aleksandr-m , Thank you for your time and comments; please let me know what do you think about below; I would like to be sure about usefulness before starting implementation. > Are you sure? Can you provide some example? Yes, I created an attack example with latest Struts2 but I think I'm not allowed to post details here so I emailed to security@struts.apache.org because the example is really can be harmful and can be applied in an almost common usage by Struts2 users. * The vulnerability is because of operating Struts inside other technologies borders! * > How knowing the name of the real class helps in that case? What are you going to do with it? Knowing that helps Struts2 to not operate inside other technologies borders which may arise some vulnerability as mentioned above. > If it is spring proxy then there are helper methods to get target class from the instance (e.g. AopUtils). If there is no clean way to do this in the Struts core utility class then it can be delegated to current object factory. Struts2 dependency of Spring is optional e.g. AopUtils is not available in core. Furthermore, Struts2 user has several options for proxy creator from cglib, jdk to any unknown third party. > Proxying the action itself is not the best practice too. Please see [This is useful, for example, if you wish to apply more complex AOP or Spring-enabled technologies, such as Acegi] ( https://struts.apache.org/docs/spring-plugin.html ). > What is the problem with generating proxy data into json? What if this is what is really needed? User may not get any exception then may not check the json result but actual result may help hackers. If this is what is really needed, then we can provide an option for user. > If ActionSupport is excluded then its methods cannot be used in the JSP (e.g. getText). In case of chain action errors / messages won't be moved to the next action. Etc. By word excluding, I meant in sensitive places rather than complete exclusion. In case of chain or any not sensitive place, we should think about solution
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/118

          I close this as more general, better, cleaner and robust resolution is implementing WW-4751(https://issues.apache.org/jira/browse/WW-4751) improvement which I am working on

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/118 I close this as more general, better, cleaner and robust resolution is implementing WW-4751 ( https://issues.apache.org/jira/browse/WW-4751 ) improvement which I am working on
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani closed the pull request at:

          https://github.com/apache/struts/pull/118

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani closed the pull request at: https://github.com/apache/struts/pull/118
          Hide
          githubbot ASF GitHub Bot added a comment -

          GitHub user yasserzamani opened a pull request:

          https://github.com/apache/struts/pull/133

          WW-4105 Considers config time class in actions chain

          I think it is `ready for merge` and does not break backward compatibility. The added `bean` attribute is and should be optional always.

          If you agree and merged this, then [784bb23](https://github.com/yasserzamani/struts/commit/784bb235e2ffcfcd7a5f2f47965ca0183e952ddd) will be a base for other possible enhancements like:

          • Considering config time class of the action in parameters interceptor enhances S2 security (details already have been submitted to `security@struts.apache.org`).
          • Considering config time class of the action in json result has similar impacts (prevents action information to be leaked to attacker).

          What do you think?

          1. Documentation
            Mainly, this is about how to deal when run time class of the action is not same as the config time, e.g. when action is proxified with a 3rd party technology or when the creation of action is with object factory. At this point, operating S2 inside that technology or object factory makes problems or potential security issues. So S2 always needs to know config time class of the action to operate in it's own borders only.

          Currently S2 uses `class` attribute for both config time class or bean name of the action inside object factory. When the user uses `class` attribute as a bean name, S2 looses this information, config time class of the action. This PR gives it back to S2 by [784bb23](https://github.com/yasserzamani/struts/commit/784bb235e2ffcfcd7a5f2f47965ca0183e952ddd) and presents a resolution for WW-4105(https://issues.apache.org/jira/browse/WW-4105) as an example which shows how to consider config time class of the action in sensitive places.

          You can merge this pull request into a Git repository by running:

          $ git pull https://github.com/yasserzamani/struts WW-4751

          Alternatively you can review and apply these changes as the patch at:

          https://github.com/apache/struts/pull/133.patch

          To close this pull request, make a commit to your master/trunk branch
          with (at least) the following in the commit message:

          This closes #133


          commit 784bb235e2ffcfcd7a5f2f47965ca0183e952ddd
          Author: Yasser Zamani <yasser.zamani@live.com>
          Date: 2017-04-20T06:29:51Z

          WW-4751 Adds optional `bean` attribute to action's config

          commit e95224f26aa17dad6ad490473b4aeab1d2ceaf79
          Author: Yasser Zamani <yasser.zamani@live.com>
          Date: 2017-04-20T18:48:53Z

          WW-4105 Considers config time class in actions chain


          Show
          githubbot ASF GitHub Bot added a comment - GitHub user yasserzamani opened a pull request: https://github.com/apache/struts/pull/133 WW-4105 Considers config time class in actions chain I think it is `ready for merge` and does not break backward compatibility. The added `bean` attribute is and should be optional always. If you agree and merged this, then [784bb23] ( https://github.com/yasserzamani/struts/commit/784bb235e2ffcfcd7a5f2f47965ca0183e952ddd ) will be a base for other possible enhancements like: Considering config time class of the action in parameters interceptor enhances S2 security (details already have been submitted to `security@struts.apache.org`). Considering config time class of the action in json result has similar impacts (prevents action information to be leaked to attacker). What do you think? Documentation Mainly, this is about how to deal when run time class of the action is not same as the config time, e.g. when action is proxified with a 3rd party technology or when the creation of action is with object factory. At this point, operating S2 inside that technology or object factory makes problems or potential security issues. So S2 always needs to know config time class of the action to operate in it's own borders only. Currently S2 uses `class` attribute for both config time class or bean name of the action inside object factory. When the user uses `class` attribute as a bean name, S2 looses this information, config time class of the action. This PR gives it back to S2 by [784bb23] ( https://github.com/yasserzamani/struts/commit/784bb235e2ffcfcd7a5f2f47965ca0183e952ddd ) and presents a resolution for WW-4105 ( https://issues.apache.org/jira/browse/WW-4105 ) as an example which shows how to consider config time class of the action in sensitive places. You can merge this pull request into a Git repository by running: $ git pull https://github.com/yasserzamani/struts WW-4751 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/struts/pull/133.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #133 commit 784bb235e2ffcfcd7a5f2f47965ca0183e952ddd Author: Yasser Zamani <yasser.zamani@live.com> Date: 2017-04-20T06:29:51Z WW-4751 Adds optional `bean` attribute to action's config commit e95224f26aa17dad6ad490473b4aeab1d2ceaf79 Author: Yasser Zamani <yasser.zamani@live.com> Date: 2017-04-20T18:48:53Z WW-4105 Considers config time class in actions chain
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user aleksandr-m commented on the issue:

          https://github.com/apache/struts/pull/133

          I'm still against adding `bean` attribute to action configuration. It is not intuitive. Chain configuration options belong to `chain` interceptor, json to `json` result, etc.
          In fact `json` result already allows to control what is serialized.

          About security, I think we can and *should* do something better than that. I.e. automatically detect proxied class and disallow to change it internals.

          Show
          githubbot ASF GitHub Bot added a comment - Github user aleksandr-m commented on the issue: https://github.com/apache/struts/pull/133 I'm still against adding `bean` attribute to action configuration. It is not intuitive. Chain configuration options belong to `chain` interceptor, json to `json` result, etc. In fact `json` result already allows to control what is serialized. About security, I think we can and * should * do something better than that. I.e. automatically detect proxied class and disallow to change it internals.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/133

          @aleksandr-m , thank you for your reply.

          > I'm still against adding bean attribute to action configuration. It is not intuitive.

          But I think using attribute `class` for both class name and bean name is not intuitive too.

          > Chain configuration options belong to chain interceptor, json to json result, etc. In fact json result already allows to control what is serialized.

          But by continuing includes/excludes approach, user has to manually concern about run time of the action. I've done #118 before. It does not have fewer changes that adding `bean` attribute.

          > About security, I think we can and should do something better than that. I.e. automatically detect proxied class and disallow to change it internals

          Yes, but so we will have to add dependency of any possible java proxy creators like Spring, cglib or etc to S2 core.

          Additionally this PR has enhanced some things automatically for example ServletUrlRenderer.java#178:
          ```
          try

          { Class clazz = formComponent.objectFactory.getClassInstance(actionConfig.getClassName()); formComponent.addParameter("actionClass", clazz); }

          catch (ClassNotFoundException e)

          { // this is OK, we'll just move on }

          ```
          Here, this PR decreases search space for validation tags by excluding proxy class when user has:
          `<s:form validate=true ...
          `

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/133 @aleksandr-m , thank you for your reply. > I'm still against adding bean attribute to action configuration. It is not intuitive. But I think using attribute `class` for both class name and bean name is not intuitive too. > Chain configuration options belong to chain interceptor, json to json result, etc. In fact json result already allows to control what is serialized. But by continuing includes/excludes approach, user has to manually concern about run time of the action. I've done #118 before. It does not have fewer changes that adding `bean` attribute. > About security, I think we can and should do something better than that. I.e. automatically detect proxied class and disallow to change it internals Yes, but so we will have to add dependency of any possible java proxy creators like Spring, cglib or etc to S2 core. Additionally this PR has enhanced some things automatically for example ServletUrlRenderer.java#178: ``` try { Class clazz = formComponent.objectFactory.getClassInstance(actionConfig.getClassName()); formComponent.addParameter("actionClass", clazz); } catch (ClassNotFoundException e) { // this is OK, we'll just move on } ``` Here, this PR decreases search space for validation tags by excluding proxy class when user has: `<s:form validate=true ... `
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user aleksandr-m commented on the issue:

          https://github.com/apache/struts/pull/133

          You're mixing two very different topics together, security and `chain` configuration.

          > But I think using attribute class for both class name and bean name is not intuitive too.

          What do you mean by that? There is no bean name.

          > But by continuing includes/excludes approach, user has to manually concern about run time of the action.

          But it the same or maybe even much more tedious manual work for defining `bean` in *every* action you want to protect.

          > I've done #118 before. It does not have fewer changes that adding bean attribute.

          It is not about the amount of changes, it is about separation of concerns. Configuration for `chain` interceptor belongs to `chain` configuration.

          > Yes, but so we will have to add dependency of any possible java proxy creators like Spring, cglib or etc to S2 core.

          Not necessarily. For example, it can be just delegated to the object factory at hand.
          Another possibility is to search for `getTarget` methods.
          Yet another is to compare action configuration `class` with the current instance `toString` / `getClass().toString`.

          Show
          githubbot ASF GitHub Bot added a comment - Github user aleksandr-m commented on the issue: https://github.com/apache/struts/pull/133 You're mixing two very different topics together, security and `chain` configuration. > But I think using attribute class for both class name and bean name is not intuitive too. What do you mean by that? There is no bean name. > But by continuing includes/excludes approach, user has to manually concern about run time of the action. But it the same or maybe even much more tedious manual work for defining `bean` in * every * action you want to protect . > I've done #118 before. It does not have fewer changes that adding bean attribute. It is not about the amount of changes, it is about separation of concerns. Configuration for `chain` interceptor belongs to `chain` configuration. > Yes, but so we will have to add dependency of any possible java proxy creators like Spring, cglib or etc to S2 core. Not necessarily. For example, it can be just delegated to the object factory at hand. Another possibility is to search for `getTarget` methods. Yet another is to compare action configuration `class` with the current instance `toString` / `getClass().toString`.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/133

          > What do you mean by that? There is no bean name.

          Users may set `class` attribute to a 1.class name or to a 2.bean name. I meant I think it is not nice to use `class` attribute for, as you say, two different topics. Additionally, in second use, S2 cannot know the config time class of the action in any clean way.

          > every action

          Not every. `bean` attribute is and will be optional. Just actions which their `class` attribute value can not be resolved to config time class of the action by `ojectfactory.getInstanceClass`. For example `<action class=beanName` with `<bean name=beanName class=com....` and if this bean is proxified e.g. by AOP needs to be protected. This PR warns about these and continue.

          > It is not about the amount of changes

          Sorry I meant about docs, satisfying user with the new design or param and maintain it for log time.

          > Yet another is to compare action configuration class with the current instance toString / getClass().toString

          As I mentioned, when user uses `class` attribute as a bean name, S2 cannot know the action configuration class in any clean way.

          > You're mixing two very different topics together, security and chain configuration.

          No, I think about S2 borders. I'm trying to discuss that S2 should or should not know the config time class of the action and then do not operate outside of that border. Input Parameters, Chain and JSON are three example operations of S2 which I discovered at first place. Then I discovered `<s:form validate=true`. I see all of these are because S2 1.does not know and 2.do not consider config time class of the action.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/133 > What do you mean by that? There is no bean name. Users may set `class` attribute to a 1.class name or to a 2.bean name. I meant I think it is not nice to use `class` attribute for, as you say, two different topics. Additionally, in second use, S2 cannot know the config time class of the action in any clean way. > every action Not every. `bean` attribute is and will be optional. Just actions which their `class` attribute value can not be resolved to config time class of the action by `ojectfactory.getInstanceClass`. For example `<action class=beanName` with `<bean name=beanName class=com....` and if this bean is proxified e.g. by AOP needs to be protected. This PR warns about these and continue. > It is not about the amount of changes Sorry I meant about docs, satisfying user with the new design or param and maintain it for log time. > Yet another is to compare action configuration class with the current instance toString / getClass().toString As I mentioned, when user uses `class` attribute as a bean name, S2 cannot know the action configuration class in any clean way. > You're mixing two very different topics together, security and chain configuration. No, I think about S2 borders. I'm trying to discuss that S2 should or should not know the config time class of the action and then do not operate outside of that border. Input Parameters, Chain and JSON are three example operations of S2 which I discovered at first place. Then I discovered `<s:form validate=true`. I see all of these are because S2 1.does not know and 2.do not consider config time class of the action.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user aleksandr-m commented on the issue:

          https://github.com/apache/struts/pull/133

          > Not every.

          Remember that issue that you've submitted to security list? All actions are affected. With this proposal `bean` attribute must be added to every action configuration in the application.

          > No, I think about S2 borders. I'm trying to discuss that S2 should or should not know the config time class of the action and then do not operate outside of that border.

          Mostly it is job of the application developer to protect sensitive data (e.g. not writing setter for `secretToken` property , excluding some parameters, etc.). The real problem is that for proxied stuff it is somehow obscure.

          > As I mentioned, when user uses class attribute as a bean name, S2 cannot know the action configuration class in any clean way.

          Even if it is not a spring bean name then it can still be affected.
          They are good enough to handle most of the cases and they can be combined to achieve better results.

          Show
          githubbot ASF GitHub Bot added a comment - Github user aleksandr-m commented on the issue: https://github.com/apache/struts/pull/133 > Not every. Remember that issue that you've submitted to security list? All actions are affected. With this proposal `bean` attribute must be added to every action configuration in the application. > No, I think about S2 borders. I'm trying to discuss that S2 should or should not know the config time class of the action and then do not operate outside of that border. Mostly it is job of the application developer to protect sensitive data (e.g. not writing setter for `secretToken` property , excluding some parameters, etc.). The real problem is that for proxied stuff it is somehow obscure. > As I mentioned, when user uses class attribute as a bean name, S2 cannot know the action configuration class in any clean way. Even if it is not a spring bean name then it can still be affected. They are good enough to handle most of the cases and they can be combined to achieve better results.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/133

          > Remember that issue that you've submitted to security list? All actions are affected. With this proposal bean attribute must be added to every action configuration in the application.

          If this proposal was made user forced to use `bean` attribute for every action, I myself was first person who rejects it. If you think so, then you are right to be worry.

          Yes I remember the issue which I submitted to security list. Maybe I misunderstood something but let count it:

          1. When action is not a bean, is not proxied, e.g. `<action class=me.yz.Action1"`: Then `objectfactory.getInstanceClass(actionCondif.getClassName())` returns `me.yz.Action1` and my proposal behaves as current S2.
          2. When action is not a bean, but is proxied, e.g. `<action class=me.yz.Action1"` and `<aop:pointcut id=actionExecute expression=execution(String me.yz.Action1.execute())`: Same as (1) `objectfactory.getInstanceClass(actionCondif.getClassName())` returns `me.yz.Action1` and my proposal behaves as current S2.
          3. When action is a bean, but is not proxied, e.g. `<action class=myAction1"` and `<bean name=myAction1 class=me.yz.Action1`: Same as (1) `objectfactory.getInstanceClass(actionCondif.getClassName())` returns `me.yz.Action1` and my proposal behaves as current S2.
          4. AND When action is a bean, and is proxied, e.g. `<action class=myAction1"` and `<bean name=myAction1 class=me.yz.Action1` and `<aop:pointcut id=actionExecute expression=execution(String me.yz.Action1.execute())`: Here `objectfactory.getInstanceClass(actionCondif.getClassName())` returns something different than `me.yz.Action1` and my proposal warns user that runtime and config time class of the action are not same and recommends the usage of `bean` attribute i.e. rewrite config to `<action class=me.yz.Action1 bean=myAction1"`.

          So only number 4 needs protection and does not fail on not usage of `bean` and just warns a log. Did I missed something?

          Thanks for your time!

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/133 > Remember that issue that you've submitted to security list? All actions are affected. With this proposal bean attribute must be added to every action configuration in the application. If this proposal was made user forced to use `bean` attribute for every action, I myself was first person who rejects it. If you think so, then you are right to be worry. Yes I remember the issue which I submitted to security list. Maybe I misunderstood something but let count it: 1. When action is not a bean, is not proxied, e.g. `<action class=me.yz.Action1"`: Then `objectfactory.getInstanceClass(actionCondif.getClassName())` returns `me.yz.Action1` and my proposal behaves as current S2. 2. When action is not a bean, but is proxied, e.g. `<action class=me.yz.Action1"` and `<aop:pointcut id=actionExecute expression=execution(String me.yz.Action1.execute())`: Same as (1) `objectfactory.getInstanceClass(actionCondif.getClassName())` returns `me.yz.Action1` and my proposal behaves as current S2. 3. When action is a bean, but is not proxied, e.g. `<action class=myAction1"` and `<bean name=myAction1 class=me.yz.Action1`: Same as (1) `objectfactory.getInstanceClass(actionCondif.getClassName())` returns `me.yz.Action1` and my proposal behaves as current S2. 4. AND When action is a bean, and is proxied, e.g. `<action class=myAction1"` and `<bean name=myAction1 class=me.yz.Action1` and `<aop:pointcut id=actionExecute expression=execution(String me.yz.Action1.execute())`: Here `objectfactory.getInstanceClass(actionCondif.getClassName())` returns something different than `me.yz.Action1` and my proposal warns user that runtime and config time class of the action are not same and recommends the usage of `bean` attribute i.e. rewrite config to `<action class=me.yz.Action1 bean=myAction1"`. So only number 4 needs protection and does not fail on not usage of `bean` and just warns a log. Did I missed something? Thanks for your time!
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/133

          1. Eureka!
            Thank you! I have found it. We can know the config time class of the action without any new thing with something like following pseudocode:
            ```
            methodName = actionConfig.getMethodName();
            if(null==methodName) methodName=ActionConfig.DEFAULT_METHOD;
            method=action.getClass().getMethod(methodName);
            configClass=method.getDeclaringClass();
            ```
            With this, attribute `bean` is not required 😃 🙌 any more, right? if so, are you pals agree with the rest of the proposal i.e. considering configClass in parameters and chain interceptors, jsonresult, `<s:form validate=true` or etc when discovered?
          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/133 Eureka! Thank you! I have found it. We can know the config time class of the action without any new thing with something like following pseudocode: ``` methodName = actionConfig.getMethodName(); if(null==methodName) methodName=ActionConfig.DEFAULT_METHOD; method=action.getClass().getMethod(methodName); configClass=method.getDeclaringClass(); ``` With this, attribute `bean` is not required 😃 🙌 any more, right? if so, are you pals agree with the rest of the proposal i.e. considering configClass in parameters and chain interceptors, jsonresult, `<s:form validate=true` or etc when discovered?
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user lukaszlenart commented on the issue:

          https://github.com/apache/struts/pull/133

          hmm... very clever `method.getDeclaringClass()` should return the proper class

          Show
          githubbot ASF GitHub Bot added a comment - Github user lukaszlenart commented on the issue: https://github.com/apache/struts/pull/133 hmm... very clever `method.getDeclaringClass()` should return the proper class
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/133

          However, today I found I should improve above pseudocode to following, because maybe user himself has extended a class and wants to use method1 from extended class in action1 and use method2 from super class in action2
          ```
          className=actionConfig.getClassName();
          if(null==className) className=action.getClass().getName();
          configClass=objectfactory.getInstanceClass(className);
          if(!configClass.getName().equals(className))

          { methodName = actionConfig.getMethodName(); if(null==methodName) methodName=ActionConfig.DEFAULT_METHOD; method=action.getClass().getMethod(methodName); configClass=method.getDeclaringClass(); }

          ```

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/133 However, today I found I should improve above pseudocode to following, because maybe user himself has extended a class and wants to use method1 from extended class in action1 and use method2 from super class in action2 ``` className=actionConfig.getClassName(); if(null==className) className=action.getClass().getName(); configClass=objectfactory.getInstanceClass(className); if(!configClass.getName().equals(className)) { methodName = actionConfig.getMethodName(); if(null==methodName) methodName=ActionConfig.DEFAULT_METHOD; method=action.getClass().getMethod(methodName); configClass=method.getDeclaringClass(); } ```
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user aleksandr-m commented on the issue:

          https://github.com/apache/struts/pull/133

          Maybe I'm doing something wrong but in my app `method.getDeclaringClass()` return proxied class as well.

          We can use something

          ```

          Show
          githubbot ASF GitHub Bot added a comment - Github user aleksandr-m commented on the issue: https://github.com/apache/struts/pull/133 Maybe I'm doing something wrong but in my app `method.getDeclaringClass()` return proxied class as well. We can use something ```
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user aleksandr-m commented on the issue:

          https://github.com/apache/struts/pull/133

          Maybe I'm doing something wrong but in my app `method.getDeclaringClass()` returns proxied class as well.

          We can use something like below. Basically same thing that `AopUtil` is doing but w/o spring classes.

          ```
          private Class<?> getTarget(Object candidate) {
          Class<?> result = null;
          try {
          Method method = candidate.getClass().getMethod("getTargetClass");
          Object obj = method.invoke(candidate);
          if (result instanceof Class)

          { result = (Class<?>) obj; }

          } catch (Exception e) {
          }
          if (result == null) {
          if (candidate.getClass().getName().contains("$$"))

          { result = candidate.getClass().getSuperclass(); }

          else

          { result = candidate.getClass(); }

          }
          return result;
          }
          ```
          And to replace `instanceof`.

          ```
          private boolean implementsInterfeace(Class<?> clazz, final String interfaceName) {
          List<Class<?>> list = org.apache.commons.lang3.ClassUtils.getAllInterfaces(clazz);
          if (list != null) {
          for (Class<?> cl : list) {
          if (interfaceName.equals(cl.getName()))

          { return true; }

          }
          }
          return false;
          }
          ```

          Show
          githubbot ASF GitHub Bot added a comment - Github user aleksandr-m commented on the issue: https://github.com/apache/struts/pull/133 Maybe I'm doing something wrong but in my app `method.getDeclaringClass()` returns proxied class as well. We can use something like below. Basically same thing that `AopUtil` is doing but w/o spring classes. ``` private Class<?> getTarget(Object candidate) { Class<?> result = null; try { Method method = candidate.getClass().getMethod("getTargetClass"); Object obj = method.invoke(candidate); if (result instanceof Class) { result = (Class<?>) obj; } } catch (Exception e) { } if (result == null) { if (candidate.getClass().getName().contains("$$")) { result = candidate.getClass().getSuperclass(); } else { result = candidate.getClass(); } } return result; } ``` And to replace `instanceof`. ``` private boolean implementsInterfeace(Class<?> clazz, final String interfaceName) { List<Class<?>> list = org.apache.commons.lang3.ClassUtils.getAllInterfaces(clazz); if (list != null) { for (Class<?> cl : list) { if (interfaceName.equals(cl.getName())) { return true; } } } return false; } ```
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/133

          I checked too. It does not work as expected on proxy classes 😞

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/133 I checked too. It does not work as expected on proxy classes 😞
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/133

          With thanks a ton to @aleksandr-m , as I checked that unwrapping Spring proxies works with reflection without any needed dependency (like @aleksandr-m mentioned above), please let me close this one.

          I will come back with a solution without the new `bean` attribute 👌

          Thanks again!

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/133 With thanks a ton to @aleksandr-m , as I checked that unwrapping Spring proxies works with reflection without any needed dependency (like @aleksandr-m mentioned above), please let me close this one. I will come back with a solution without the new `bean` attribute 👌 Thanks again!
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani closed the pull request at:

          https://github.com/apache/struts/pull/133

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani closed the pull request at: https://github.com/apache/struts/pull/133
          Hide
          githubbot ASF GitHub Bot added a comment -

          GitHub user yasserzamani opened a pull request:

          https://github.com/apache/struts/pull/135

          WW-4105 Unwraps Spring proxy in actions chain

          Resolves WW-4105(https://issues.apache.org/jira/browse/WW-4105).

          You can merge this pull request into a Git repository by running:

          $ git pull https://github.com/yasserzamani/struts WW-4105_2

          Alternatively you can review and apply these changes as the patch at:

          https://github.com/apache/struts/pull/135.patch

          To close this pull request, make a commit to your master/trunk branch
          with (at least) the following in the commit message:

          This closes #135


          commit c2f2de06ce3c5545878a3b421fdde3ca5495d3cc
          Author: Yasser Zamani <yasser.zamani@live.com>
          Date: 2017-04-30T04:50:57Z

          WW-4105 Unwraps Spring proxy in actions chain


          Show
          githubbot ASF GitHub Bot added a comment - GitHub user yasserzamani opened a pull request: https://github.com/apache/struts/pull/135 WW-4105 Unwraps Spring proxy in actions chain Resolves WW-4105 ( https://issues.apache.org/jira/browse/WW-4105 ). You can merge this pull request into a Git repository by running: $ git pull https://github.com/yasserzamani/struts WW-4105 _2 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/struts/pull/135.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #135 commit c2f2de06ce3c5545878a3b421fdde3ca5495d3cc Author: Yasser Zamani <yasser.zamani@live.com> Date: 2017-04-30T04:50:57Z WW-4105 Unwraps Spring proxy in actions chain
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user aleksandr-m commented on a diff in the pull request:

          https://github.com/apache/struts/pull/135#discussion_r114109147

          — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java —
          @@ -0,0 +1,89 @@
          +/*
          + * Copyright 2017 The Apache Software Foundation.
          + *
          + * Licensed under the Apache License, Version 2.0 (the "License");
          + * you may not use this file except in compliance with the License.
          + * You may obtain a copy of the License at
          + *
          + * http://www.apache.org/licenses/LICENSE-2.0
          + *
          + * Unless required by applicable law or agreed to in writing, software
          + * distributed under the License is distributed on an "AS IS" BASIS,
          + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          + * See the License for the specific language governing permissions and
          + * limitations under the License.
          + */
          +package com.opensymphony.xwork2.spring;
          +
          +import com.opensymphony.xwork2.util.ClassLoaderUtil;
          +import org.apache.commons.lang3.reflect.MethodUtils;
          +
          +import java.lang.reflect.Proxy;
          +
          +/**
          + * <code>SpringUtils</code>
          + * <p>
          + * Various utility methods dealing with spring framework
          + * </p>
          + *
          + */
          +public class SpringUtils {
          — End diff –

          Maybe name it `ProxyUtil` or something like that. This class can be used to deal with known proxies and not only spring proxies.

          Show
          githubbot ASF GitHub Bot added a comment - Github user aleksandr-m commented on a diff in the pull request: https://github.com/apache/struts/pull/135#discussion_r114109147 — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java — @@ -0,0 +1,89 @@ +/* + * Copyright 2017 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import org.apache.commons.lang3.reflect.MethodUtils; + +import java.lang.reflect.Proxy; + +/** + * <code>SpringUtils</code> + * <p> + * Various utility methods dealing with spring framework + * </p> + * + */ +public class SpringUtils { — End diff – Maybe name it `ProxyUtil` or something like that. This class can be used to deal with known proxies and not only spring proxies.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user aleksandr-m commented on a diff in the pull request:

          https://github.com/apache/struts/pull/135#discussion_r114109235

          — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java —
          @@ -0,0 +1,89 @@
          +/*
          + * Copyright 2017 The Apache Software Foundation.
          + *
          + * Licensed under the Apache License, Version 2.0 (the "License");
          + * you may not use this file except in compliance with the License.
          + * You may obtain a copy of the License at
          + *
          + * http://www.apache.org/licenses/LICENSE-2.0
          + *
          + * Unless required by applicable law or agreed to in writing, software
          + * distributed under the License is distributed on an "AS IS" BASIS,
          + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          + * See the License for the specific language governing permissions and
          + * limitations under the License.
          + */
          +package com.opensymphony.xwork2.spring;
          +
          +import com.opensymphony.xwork2.util.ClassLoaderUtil;
          +import org.apache.commons.lang3.reflect.MethodUtils;
          +
          +import java.lang.reflect.Proxy;
          +
          +/**
          + * <code>SpringUtils</code>
          + * <p>
          + * Various utility methods dealing with spring framework
          + * </p>
          + *
          + */
          +public class SpringUtils {
          + /**
          + * Get the ultimate <em>target</em> object of the supplied

          {@code candidate}
          + * object, unwrapping not only a top-level proxy but also any number of
          + * nested proxies.
          + * <p>If the supplied {@code candidate}

          is a Spring proxy, the ultimate target of all
          + * nested proxies will be returned; otherwise, the

          {@code candidate}
          + * will be returned <em>as is</em>.
          + * @param candidate the instance to check (potentially a Spring AOP proxy;
          + * never {@code null})
          + * @return the target object or the {@code candidate}

          (never

          {@code null}

          )
          + * @throws IllegalStateException if an error occurs while unwrapping a proxy
          + */
          + public static <T> T getUltimateTargetObject(Object candidate) {
          + try {
          + if (isAopProxy(candidate) &&
          + implementsInterface(candidate.getClass(), "org.springframework.aop.framework.Advised")) {
          + Object targetSource = MethodUtils.invokeMethod(candidate, "getTargetSource");
          — End diff –

          What is `targetSource` here?

          Show
          githubbot ASF GitHub Bot added a comment - Github user aleksandr-m commented on a diff in the pull request: https://github.com/apache/struts/pull/135#discussion_r114109235 — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java — @@ -0,0 +1,89 @@ +/* + * Copyright 2017 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import org.apache.commons.lang3.reflect.MethodUtils; + +import java.lang.reflect.Proxy; + +/** + * <code>SpringUtils</code> + * <p> + * Various utility methods dealing with spring framework + * </p> + * + */ +public class SpringUtils { + /** + * Get the ultimate <em>target</em> object of the supplied {@code candidate} + * object, unwrapping not only a top-level proxy but also any number of + * nested proxies. + * <p>If the supplied {@code candidate} is a Spring proxy, the ultimate target of all + * nested proxies will be returned; otherwise, the {@code candidate} + * will be returned <em>as is</em>. + * @param candidate the instance to check (potentially a Spring AOP proxy; + * never {@code null}) + * @return the target object or the {@code candidate} (never {@code null} ) + * @throws IllegalStateException if an error occurs while unwrapping a proxy + */ + public static <T> T getUltimateTargetObject(Object candidate) { + try { + if (isAopProxy(candidate) && + implementsInterface(candidate.getClass(), "org.springframework.aop.framework.Advised")) { + Object targetSource = MethodUtils.invokeMethod(candidate, "getTargetSource"); — End diff – What is `targetSource` here?
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user aleksandr-m commented on a diff in the pull request:

          https://github.com/apache/struts/pull/135#discussion_r114109357

          — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java —
          @@ -0,0 +1,89 @@
          +/*
          + * Copyright 2017 The Apache Software Foundation.
          + *
          + * Licensed under the Apache License, Version 2.0 (the "License");
          + * you may not use this file except in compliance with the License.
          + * You may obtain a copy of the License at
          + *
          + * http://www.apache.org/licenses/LICENSE-2.0
          + *
          + * Unless required by applicable law or agreed to in writing, software
          + * distributed under the License is distributed on an "AS IS" BASIS,
          + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          + * See the License for the specific language governing permissions and
          + * limitations under the License.
          + */
          +package com.opensymphony.xwork2.spring;
          +
          +import com.opensymphony.xwork2.util.ClassLoaderUtil;
          +import org.apache.commons.lang3.reflect.MethodUtils;
          +
          +import java.lang.reflect.Proxy;
          +
          +/**
          + * <code>SpringUtils</code>
          + * <p>
          + * Various utility methods dealing with spring framework
          + * </p>
          + *
          + */
          +public class SpringUtils {
          + /**
          + * Get the ultimate <em>target</em> object of the supplied

          {@code candidate}
          + * object, unwrapping not only a top-level proxy but also any number of
          + * nested proxies.
          + * <p>If the supplied {@code candidate}

          is a Spring proxy, the ultimate target of all
          + * nested proxies will be returned; otherwise, the

          {@code candidate}
          + * will be returned <em>as is</em>.
          + * @param candidate the instance to check (potentially a Spring AOP proxy;
          + * never {@code null})
          + * @return the target object or the {@code candidate}

          (never

          {@code null}

          )
          + * @throws IllegalStateException if an error occurs while unwrapping a proxy
          + */
          + public static <T> T getUltimateTargetObject(Object candidate) {
          + try {
          + if (isAopProxy(candidate) &&
          + implementsInterface(candidate.getClass(), "org.springframework.aop.framework.Advised"))

          { + Object targetSource = MethodUtils.invokeMethod(candidate, "getTargetSource"); + Object target = MethodUtils.invokeMethod(targetSource, "getTarget"); + return getUltimateTargetObject(target); + }

          + }
          + catch (Throwable ex)

          { + throw new IllegalStateException("Failed to unwrap proxied object", ex); + }

          + return (T) candidate;
          + }
          +
          + /**
          + * Check whether the given object is a Spring proxy.
          + * @param object the object to check
          + */
          + public static boolean isAopProxy(Object object) {
          + Class<?> clazz = object.getClass();
          + return (implementsInterface(clazz, "org.springframework.aop.SpringProxy") &&
          — End diff –

          Extract strings to constants.

          Show
          githubbot ASF GitHub Bot added a comment - Github user aleksandr-m commented on a diff in the pull request: https://github.com/apache/struts/pull/135#discussion_r114109357 — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java — @@ -0,0 +1,89 @@ +/* + * Copyright 2017 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import org.apache.commons.lang3.reflect.MethodUtils; + +import java.lang.reflect.Proxy; + +/** + * <code>SpringUtils</code> + * <p> + * Various utility methods dealing with spring framework + * </p> + * + */ +public class SpringUtils { + /** + * Get the ultimate <em>target</em> object of the supplied {@code candidate} + * object, unwrapping not only a top-level proxy but also any number of + * nested proxies. + * <p>If the supplied {@code candidate} is a Spring proxy, the ultimate target of all + * nested proxies will be returned; otherwise, the {@code candidate} + * will be returned <em>as is</em>. + * @param candidate the instance to check (potentially a Spring AOP proxy; + * never {@code null}) + * @return the target object or the {@code candidate} (never {@code null} ) + * @throws IllegalStateException if an error occurs while unwrapping a proxy + */ + public static <T> T getUltimateTargetObject(Object candidate) { + try { + if (isAopProxy(candidate) && + implementsInterface(candidate.getClass(), "org.springframework.aop.framework.Advised")) { + Object targetSource = MethodUtils.invokeMethod(candidate, "getTargetSource"); + Object target = MethodUtils.invokeMethod(targetSource, "getTarget"); + return getUltimateTargetObject(target); + } + } + catch (Throwable ex) { + throw new IllegalStateException("Failed to unwrap proxied object", ex); + } + return (T) candidate; + } + + /** + * Check whether the given object is a Spring proxy. + * @param object the object to check + */ + public static boolean isAopProxy(Object object) { + Class<?> clazz = object.getClass(); + return (implementsInterface(clazz, "org.springframework.aop.SpringProxy") && — End diff – Extract strings to constants.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user aleksandr-m commented on a diff in the pull request:

          https://github.com/apache/struts/pull/135#discussion_r114109604

          — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java —
          @@ -0,0 +1,89 @@
          +/*
          + * Copyright 2017 The Apache Software Foundation.
          + *
          + * Licensed under the Apache License, Version 2.0 (the "License");
          + * you may not use this file except in compliance with the License.
          + * You may obtain a copy of the License at
          + *
          + * http://www.apache.org/licenses/LICENSE-2.0
          + *
          + * Unless required by applicable law or agreed to in writing, software
          + * distributed under the License is distributed on an "AS IS" BASIS,
          + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          + * See the License for the specific language governing permissions and
          + * limitations under the License.
          + */
          +package com.opensymphony.xwork2.spring;
          +
          +import com.opensymphony.xwork2.util.ClassLoaderUtil;
          +import org.apache.commons.lang3.reflect.MethodUtils;
          +
          +import java.lang.reflect.Proxy;
          +
          +/**
          + * <code>SpringUtils</code>
          + * <p>
          + * Various utility methods dealing with spring framework
          + * </p>
          + *
          + */
          +public class SpringUtils {
          — End diff –

          Another maybe. This can be turned to injectable bean so it can be easily overridable if needed. Wdyt?

          Show
          githubbot ASF GitHub Bot added a comment - Github user aleksandr-m commented on a diff in the pull request: https://github.com/apache/struts/pull/135#discussion_r114109604 — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java — @@ -0,0 +1,89 @@ +/* + * Copyright 2017 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import org.apache.commons.lang3.reflect.MethodUtils; + +import java.lang.reflect.Proxy; + +/** + * <code>SpringUtils</code> + * <p> + * Various utility methods dealing with spring framework + * </p> + * + */ +public class SpringUtils { — End diff – Another maybe. This can be turned to injectable bean so it can be easily overridable if needed. Wdyt?
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on a diff in the pull request:

          https://github.com/apache/struts/pull/135#discussion_r114115352

          — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java —
          @@ -0,0 +1,89 @@
          +/*
          + * Copyright 2017 The Apache Software Foundation.
          + *
          + * Licensed under the Apache License, Version 2.0 (the "License");
          + * you may not use this file except in compliance with the License.
          + * You may obtain a copy of the License at
          + *
          + * http://www.apache.org/licenses/LICENSE-2.0
          + *
          + * Unless required by applicable law or agreed to in writing, software
          + * distributed under the License is distributed on an "AS IS" BASIS,
          + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          + * See the License for the specific language governing permissions and
          + * limitations under the License.
          + */
          +package com.opensymphony.xwork2.spring;
          +
          +import com.opensymphony.xwork2.util.ClassLoaderUtil;
          +import org.apache.commons.lang3.reflect.MethodUtils;
          +
          +import java.lang.reflect.Proxy;
          +
          +/**
          + * <code>SpringUtils</code>
          + * <p>
          + * Various utility methods dealing with spring framework
          + * </p>
          + *
          + */
          +public class SpringUtils {
          + /**
          + * Get the ultimate <em>target</em> object of the supplied

          {@code candidate}
          + * object, unwrapping not only a top-level proxy but also any number of
          + * nested proxies.
          + * <p>If the supplied {@code candidate}

          is a Spring proxy, the ultimate target of all
          + * nested proxies will be returned; otherwise, the

          {@code candidate}
          + * will be returned <em>as is</em>.
          + * @param candidate the instance to check (potentially a Spring AOP proxy;
          + * never {@code null})
          + * @return the target object or the {@code candidate}

          (never

          {@code null}

          )
          + * @throws IllegalStateException if an error occurs while unwrapping a proxy
          + */
          + public static <T> T getUltimateTargetObject(Object candidate) {
          + try {
          + if (isAopProxy(candidate) &&
          + implementsInterface(candidate.getClass(), "org.springframework.aop.framework.Advised")) {
          + Object targetSource = MethodUtils.invokeMethod(candidate, "getTargetSource");
          — End diff –

          It is what Spring himself does to unwrap it's proxies. Please see [AopTestUtils.java](https://github.com/spring-projects/spring-framework/blob/master/spring-test/src/main/java/org/springframework/test/util/AopTestUtils.java)

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on a diff in the pull request: https://github.com/apache/struts/pull/135#discussion_r114115352 — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java — @@ -0,0 +1,89 @@ +/* + * Copyright 2017 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import org.apache.commons.lang3.reflect.MethodUtils; + +import java.lang.reflect.Proxy; + +/** + * <code>SpringUtils</code> + * <p> + * Various utility methods dealing with spring framework + * </p> + * + */ +public class SpringUtils { + /** + * Get the ultimate <em>target</em> object of the supplied {@code candidate} + * object, unwrapping not only a top-level proxy but also any number of + * nested proxies. + * <p>If the supplied {@code candidate} is a Spring proxy, the ultimate target of all + * nested proxies will be returned; otherwise, the {@code candidate} + * will be returned <em>as is</em>. + * @param candidate the instance to check (potentially a Spring AOP proxy; + * never {@code null}) + * @return the target object or the {@code candidate} (never {@code null} ) + * @throws IllegalStateException if an error occurs while unwrapping a proxy + */ + public static <T> T getUltimateTargetObject(Object candidate) { + try { + if (isAopProxy(candidate) && + implementsInterface(candidate.getClass(), "org.springframework.aop.framework.Advised")) { + Object targetSource = MethodUtils.invokeMethod(candidate, "getTargetSource"); — End diff – It is what Spring himself does to unwrap it's proxies. Please see [AopTestUtils.java] ( https://github.com/spring-projects/spring-framework/blob/master/spring-test/src/main/java/org/springframework/test/util/AopTestUtils.java )
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on a diff in the pull request:

          https://github.com/apache/struts/pull/135#discussion_r114115548

          — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java —
          @@ -0,0 +1,89 @@
          +/*
          + * Copyright 2017 The Apache Software Foundation.
          + *
          + * Licensed under the Apache License, Version 2.0 (the "License");
          + * you may not use this file except in compliance with the License.
          + * You may obtain a copy of the License at
          + *
          + * http://www.apache.org/licenses/LICENSE-2.0
          + *
          + * Unless required by applicable law or agreed to in writing, software
          + * distributed under the License is distributed on an "AS IS" BASIS,
          + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          + * See the License for the specific language governing permissions and
          + * limitations under the License.
          + */
          +package com.opensymphony.xwork2.spring;
          +
          +import com.opensymphony.xwork2.util.ClassLoaderUtil;
          +import org.apache.commons.lang3.reflect.MethodUtils;
          +
          +import java.lang.reflect.Proxy;
          +
          +/**
          + * <code>SpringUtils</code>
          + * <p>
          + * Various utility methods dealing with spring framework
          + * </p>
          + *
          + */
          +public class SpringUtils {
          — End diff –

          Why someone may need to override such specific methods?

          As all methods could be static, I thought normally it should be a static utils class rather than a bean object.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on a diff in the pull request: https://github.com/apache/struts/pull/135#discussion_r114115548 — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java — @@ -0,0 +1,89 @@ +/* + * Copyright 2017 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import org.apache.commons.lang3.reflect.MethodUtils; + +import java.lang.reflect.Proxy; + +/** + * <code>SpringUtils</code> + * <p> + * Various utility methods dealing with spring framework + * </p> + * + */ +public class SpringUtils { — End diff – Why someone may need to override such specific methods? As all methods could be static, I thought normally it should be a static utils class rather than a bean object.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on a diff in the pull request:

          https://github.com/apache/struts/pull/135#discussion_r114115598

          — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java —
          @@ -0,0 +1,89 @@
          +/*
          + * Copyright 2017 The Apache Software Foundation.
          + *
          + * Licensed under the Apache License, Version 2.0 (the "License");
          + * you may not use this file except in compliance with the License.
          + * You may obtain a copy of the License at
          + *
          + * http://www.apache.org/licenses/LICENSE-2.0
          + *
          + * Unless required by applicable law or agreed to in writing, software
          + * distributed under the License is distributed on an "AS IS" BASIS,
          + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          + * See the License for the specific language governing permissions and
          + * limitations under the License.
          + */
          +package com.opensymphony.xwork2.spring;
          +
          +import com.opensymphony.xwork2.util.ClassLoaderUtil;
          +import org.apache.commons.lang3.reflect.MethodUtils;
          +
          +import java.lang.reflect.Proxy;
          +
          +/**
          + * <code>SpringUtils</code>
          + * <p>
          + * Various utility methods dealing with spring framework
          + * </p>
          + *
          + */
          +public class SpringUtils {
          + /**
          + * Get the ultimate <em>target</em> object of the supplied

          {@code candidate}
          + * object, unwrapping not only a top-level proxy but also any number of
          + * nested proxies.
          + * <p>If the supplied {@code candidate}

          is a Spring proxy, the ultimate target of all
          + * nested proxies will be returned; otherwise, the

          {@code candidate}
          + * will be returned <em>as is</em>.
          + * @param candidate the instance to check (potentially a Spring AOP proxy;
          + * never {@code null})
          + * @return the target object or the {@code candidate}

          (never

          {@code null}

          )
          + * @throws IllegalStateException if an error occurs while unwrapping a proxy
          + */
          + public static <T> T getUltimateTargetObject(Object candidate) {
          + try {
          + if (isAopProxy(candidate) &&
          + implementsInterface(candidate.getClass(), "org.springframework.aop.framework.Advised"))

          { + Object targetSource = MethodUtils.invokeMethod(candidate, "getTargetSource"); + Object target = MethodUtils.invokeMethod(targetSource, "getTarget"); + return getUltimateTargetObject(target); + }

          + }
          + catch (Throwable ex)

          { + throw new IllegalStateException("Failed to unwrap proxied object", ex); + }

          + return (T) candidate;
          + }
          +
          + /**
          + * Check whether the given object is a Spring proxy.
          + * @param object the object to check
          + */
          + public static boolean isAopProxy(Object object) {
          + Class<?> clazz = object.getClass();
          + return (implementsInterface(clazz, "org.springframework.aop.SpringProxy") &&
          — End diff –

          Thank you! I will do in next commit.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on a diff in the pull request: https://github.com/apache/struts/pull/135#discussion_r114115598 — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java — @@ -0,0 +1,89 @@ +/* + * Copyright 2017 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import org.apache.commons.lang3.reflect.MethodUtils; + +import java.lang.reflect.Proxy; + +/** + * <code>SpringUtils</code> + * <p> + * Various utility methods dealing with spring framework + * </p> + * + */ +public class SpringUtils { + /** + * Get the ultimate <em>target</em> object of the supplied {@code candidate} + * object, unwrapping not only a top-level proxy but also any number of + * nested proxies. + * <p>If the supplied {@code candidate} is a Spring proxy, the ultimate target of all + * nested proxies will be returned; otherwise, the {@code candidate} + * will be returned <em>as is</em>. + * @param candidate the instance to check (potentially a Spring AOP proxy; + * never {@code null}) + * @return the target object or the {@code candidate} (never {@code null} ) + * @throws IllegalStateException if an error occurs while unwrapping a proxy + */ + public static <T> T getUltimateTargetObject(Object candidate) { + try { + if (isAopProxy(candidate) && + implementsInterface(candidate.getClass(), "org.springframework.aop.framework.Advised")) { + Object targetSource = MethodUtils.invokeMethod(candidate, "getTargetSource"); + Object target = MethodUtils.invokeMethod(targetSource, "getTarget"); + return getUltimateTargetObject(target); + } + } + catch (Throwable ex) { + throw new IllegalStateException("Failed to unwrap proxied object", ex); + } + return (T) candidate; + } + + /** + * Check whether the given object is a Spring proxy. + * @param object the object to check + */ + public static boolean isAopProxy(Object object) { + Class<?> clazz = object.getClass(); + return (implementsInterface(clazz, "org.springframework.aop.SpringProxy") && — End diff – Thank you! I will do in next commit.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on a diff in the pull request:

          https://github.com/apache/struts/pull/135#discussion_r114115750

          — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java —
          @@ -0,0 +1,89 @@
          +/*
          + * Copyright 2017 The Apache Software Foundation.
          + *
          + * Licensed under the Apache License, Version 2.0 (the "License");
          + * you may not use this file except in compliance with the License.
          + * You may obtain a copy of the License at
          + *
          + * http://www.apache.org/licenses/LICENSE-2.0
          + *
          + * Unless required by applicable law or agreed to in writing, software
          + * distributed under the License is distributed on an "AS IS" BASIS,
          + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          + * See the License for the specific language governing permissions and
          + * limitations under the License.
          + */
          +package com.opensymphony.xwork2.spring;
          +
          +import com.opensymphony.xwork2.util.ClassLoaderUtil;
          +import org.apache.commons.lang3.reflect.MethodUtils;
          +
          +import java.lang.reflect.Proxy;
          +
          +/**
          + * <code>SpringUtils</code>
          + * <p>
          + * Various utility methods dealing with spring framework
          + * </p>
          + *
          + */
          +public class SpringUtils {
          — End diff –

          Thank you! I will do in next commit. However, I also try my effort to remove it to commons-lang if guys there accepted.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on a diff in the pull request: https://github.com/apache/struts/pull/135#discussion_r114115750 — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java — @@ -0,0 +1,89 @@ +/* + * Copyright 2017 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import org.apache.commons.lang3.reflect.MethodUtils; + +import java.lang.reflect.Proxy; + +/** + * <code>SpringUtils</code> + * <p> + * Various utility methods dealing with spring framework + * </p> + * + */ +public class SpringUtils { — End diff – Thank you! I will do in next commit. However, I also try my effort to remove it to commons-lang if guys there accepted.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user aleksandr-m commented on a diff in the pull request:

          https://github.com/apache/struts/pull/135#discussion_r114148402

          — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java —
          @@ -0,0 +1,89 @@
          +/*
          + * Copyright 2017 The Apache Software Foundation.
          + *
          + * Licensed under the Apache License, Version 2.0 (the "License");
          + * you may not use this file except in compliance with the License.
          + * You may obtain a copy of the License at
          + *
          + * http://www.apache.org/licenses/LICENSE-2.0
          + *
          + * Unless required by applicable law or agreed to in writing, software
          + * distributed under the License is distributed on an "AS IS" BASIS,
          + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          + * See the License for the specific language governing permissions and
          + * limitations under the License.
          + */
          +package com.opensymphony.xwork2.spring;
          +
          +import com.opensymphony.xwork2.util.ClassLoaderUtil;
          +import org.apache.commons.lang3.reflect.MethodUtils;
          +
          +import java.lang.reflect.Proxy;
          +
          +/**
          + * <code>SpringUtils</code>
          + * <p>
          + * Various utility methods dealing with spring framework
          + * </p>
          + *
          + */
          +public class SpringUtils {
          + /**
          + * Get the ultimate <em>target</em> object of the supplied

          {@code candidate}
          + * object, unwrapping not only a top-level proxy but also any number of
          + * nested proxies.
          + * <p>If the supplied {@code candidate}

          is a Spring proxy, the ultimate target of all
          + * nested proxies will be returned; otherwise, the

          {@code candidate}
          + * will be returned <em>as is</em>.
          + * @param candidate the instance to check (potentially a Spring AOP proxy;
          + * never {@code null})
          + * @return the target object or the {@code candidate}

          (never

          {@code null}

          )
          + * @throws IllegalStateException if an error occurs while unwrapping a proxy
          + */
          + public static <T> T getUltimateTargetObject(Object candidate) {
          + try {
          + if (isAopProxy(candidate) &&
          + implementsInterface(candidate.getClass(), "org.springframework.aop.framework.Advised")) {
          + Object targetSource = MethodUtils.invokeMethod(candidate, "getTargetSource");
          — End diff –

          Hmm... Never used `AopTestUtils`. But `Advised` extends `TargetClassAware`. Can `getTargetClass` just be invoked instead of two method calls? See [`AopUtils`](https://github.com/spring-projects/spring-framework/blob/master/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java).

          Show
          githubbot ASF GitHub Bot added a comment - Github user aleksandr-m commented on a diff in the pull request: https://github.com/apache/struts/pull/135#discussion_r114148402 — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java — @@ -0,0 +1,89 @@ +/* + * Copyright 2017 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import org.apache.commons.lang3.reflect.MethodUtils; + +import java.lang.reflect.Proxy; + +/** + * <code>SpringUtils</code> + * <p> + * Various utility methods dealing with spring framework + * </p> + * + */ +public class SpringUtils { + /** + * Get the ultimate <em>target</em> object of the supplied {@code candidate} + * object, unwrapping not only a top-level proxy but also any number of + * nested proxies. + * <p>If the supplied {@code candidate} is a Spring proxy, the ultimate target of all + * nested proxies will be returned; otherwise, the {@code candidate} + * will be returned <em>as is</em>. + * @param candidate the instance to check (potentially a Spring AOP proxy; + * never {@code null}) + * @return the target object or the {@code candidate} (never {@code null} ) + * @throws IllegalStateException if an error occurs while unwrapping a proxy + */ + public static <T> T getUltimateTargetObject(Object candidate) { + try { + if (isAopProxy(candidate) && + implementsInterface(candidate.getClass(), "org.springframework.aop.framework.Advised")) { + Object targetSource = MethodUtils.invokeMethod(candidate, "getTargetSource"); — End diff – Hmm... Never used `AopTestUtils`. But `Advised` extends `TargetClassAware`. Can `getTargetClass` just be invoked instead of two method calls? See [`AopUtils`] ( https://github.com/spring-projects/spring-framework/blob/master/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java ).
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user aleksandr-m commented on a diff in the pull request:

          https://github.com/apache/struts/pull/135#discussion_r114148973

          — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java —
          @@ -0,0 +1,89 @@
          +/*
          + * Copyright 2017 The Apache Software Foundation.
          + *
          + * Licensed under the Apache License, Version 2.0 (the "License");
          + * you may not use this file except in compliance with the License.
          + * You may obtain a copy of the License at
          + *
          + * http://www.apache.org/licenses/LICENSE-2.0
          + *
          + * Unless required by applicable law or agreed to in writing, software
          + * distributed under the License is distributed on an "AS IS" BASIS,
          + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          + * See the License for the specific language governing permissions and
          + * limitations under the License.
          + */
          +package com.opensymphony.xwork2.spring;
          +
          +import com.opensymphony.xwork2.util.ClassLoaderUtil;
          +import org.apache.commons.lang3.reflect.MethodUtils;
          +
          +import java.lang.reflect.Proxy;
          +
          +/**
          + * <code>SpringUtils</code>
          + * <p>
          + * Various utility methods dealing with spring framework
          + * </p>
          + *
          + */
          +public class SpringUtils {
          — End diff –

          To support other possible proxies. Or in case something changes in spring-aop.

          Show
          githubbot ASF GitHub Bot added a comment - Github user aleksandr-m commented on a diff in the pull request: https://github.com/apache/struts/pull/135#discussion_r114148973 — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java — @@ -0,0 +1,89 @@ +/* + * Copyright 2017 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import org.apache.commons.lang3.reflect.MethodUtils; + +import java.lang.reflect.Proxy; + +/** + * <code>SpringUtils</code> + * <p> + * Various utility methods dealing with spring framework + * </p> + * + */ +public class SpringUtils { — End diff – To support other possible proxies. Or in case something changes in spring-aop.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on a diff in the pull request:

          https://github.com/apache/struts/pull/135#discussion_r114155980

          — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java —
          @@ -0,0 +1,89 @@
          +/*
          + * Copyright 2017 The Apache Software Foundation.
          + *
          + * Licensed under the Apache License, Version 2.0 (the "License");
          + * you may not use this file except in compliance with the License.
          + * You may obtain a copy of the License at
          + *
          + * http://www.apache.org/licenses/LICENSE-2.0
          + *
          + * Unless required by applicable law or agreed to in writing, software
          + * distributed under the License is distributed on an "AS IS" BASIS,
          + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          + * See the License for the specific language governing permissions and
          + * limitations under the License.
          + */
          +package com.opensymphony.xwork2.spring;
          +
          +import com.opensymphony.xwork2.util.ClassLoaderUtil;
          +import org.apache.commons.lang3.reflect.MethodUtils;
          +
          +import java.lang.reflect.Proxy;
          +
          +/**
          + * <code>SpringUtils</code>
          + * <p>
          + * Various utility methods dealing with spring framework
          + * </p>
          + *
          + */
          +public class SpringUtils {
          + /**
          + * Get the ultimate <em>target</em> object of the supplied

          {@code candidate}
          + * object, unwrapping not only a top-level proxy but also any number of
          + * nested proxies.
          + * <p>If the supplied {@code candidate}

          is a Spring proxy, the ultimate target of all
          + * nested proxies will be returned; otherwise, the

          {@code candidate}
          + * will be returned <em>as is</em>.
          + * @param candidate the instance to check (potentially a Spring AOP proxy;
          + * never {@code null})
          + * @return the target object or the {@code candidate}

          (never

          {@code null}

          )
          + * @throws IllegalStateException if an error occurs while unwrapping a proxy
          + */
          + public static <T> T getUltimateTargetObject(Object candidate) {
          + try {
          + if (isAopProxy(candidate) &&
          + implementsInterface(candidate.getClass(), "org.springframework.aop.framework.Advised")) {
          + Object targetSource = MethodUtils.invokeMethod(candidate, "getTargetSource");
          — End diff –

          `getTargetClass` just returns a `Class` but getting thae target `Object` (i.e. actual action object) let us pass it directly to `ReflectionProvider` without any needed modification of `ReflectionProvider` codes.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on a diff in the pull request: https://github.com/apache/struts/pull/135#discussion_r114155980 — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java — @@ -0,0 +1,89 @@ +/* + * Copyright 2017 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import org.apache.commons.lang3.reflect.MethodUtils; + +import java.lang.reflect.Proxy; + +/** + * <code>SpringUtils</code> + * <p> + * Various utility methods dealing with spring framework + * </p> + * + */ +public class SpringUtils { + /** + * Get the ultimate <em>target</em> object of the supplied {@code candidate} + * object, unwrapping not only a top-level proxy but also any number of + * nested proxies. + * <p>If the supplied {@code candidate} is a Spring proxy, the ultimate target of all + * nested proxies will be returned; otherwise, the {@code candidate} + * will be returned <em>as is</em>. + * @param candidate the instance to check (potentially a Spring AOP proxy; + * never {@code null}) + * @return the target object or the {@code candidate} (never {@code null} ) + * @throws IllegalStateException if an error occurs while unwrapping a proxy + */ + public static <T> T getUltimateTargetObject(Object candidate) { + try { + if (isAopProxy(candidate) && + implementsInterface(candidate.getClass(), "org.springframework.aop.framework.Advised")) { + Object targetSource = MethodUtils.invokeMethod(candidate, "getTargetSource"); — End diff – `getTargetClass` just returns a `Class` but getting thae target `Object` (i.e. actual action object) let us pass it directly to `ReflectionProvider` without any needed modification of `ReflectionProvider` codes.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on a diff in the pull request:

          https://github.com/apache/struts/pull/135#discussion_r114156448

          — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java —
          @@ -0,0 +1,89 @@
          +/*
          + * Copyright 2017 The Apache Software Foundation.
          + *
          + * Licensed under the Apache License, Version 2.0 (the "License");
          + * you may not use this file except in compliance with the License.
          + * You may obtain a copy of the License at
          + *
          + * http://www.apache.org/licenses/LICENSE-2.0
          + *
          + * Unless required by applicable law or agreed to in writing, software
          + * distributed under the License is distributed on an "AS IS" BASIS,
          + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          + * See the License for the specific language governing permissions and
          + * limitations under the License.
          + */
          +package com.opensymphony.xwork2.spring;
          +
          +import com.opensymphony.xwork2.util.ClassLoaderUtil;
          +import org.apache.commons.lang3.reflect.MethodUtils;
          +
          +import java.lang.reflect.Proxy;
          +
          +/**
          + * <code>SpringUtils</code>
          + * <p>
          + * Various utility methods dealing with spring framework
          + * </p>
          + *
          + */
          +public class SpringUtils {
          — End diff –

          I think we should update Struts itself in both cases when reported by a user.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on a diff in the pull request: https://github.com/apache/struts/pull/135#discussion_r114156448 — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java — @@ -0,0 +1,89 @@ +/* + * Copyright 2017 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import org.apache.commons.lang3.reflect.MethodUtils; + +import java.lang.reflect.Proxy; + +/** + * <code>SpringUtils</code> + * <p> + * Various utility methods dealing with spring framework + * </p> + * + */ +public class SpringUtils { — End diff – I think we should update Struts itself in both cases when reported by a user.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user lukaszlenart commented on a diff in the pull request:

          https://github.com/apache/struts/pull/135#discussion_r115664014

          — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java —
          @@ -0,0 +1,89 @@
          +/*
          + * Copyright 2017 The Apache Software Foundation.
          + *
          + * Licensed under the Apache License, Version 2.0 (the "License");
          + * you may not use this file except in compliance with the License.
          + * You may obtain a copy of the License at
          + *
          + * http://www.apache.org/licenses/LICENSE-2.0
          + *
          + * Unless required by applicable law or agreed to in writing, software
          + * distributed under the License is distributed on an "AS IS" BASIS,
          + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          + * See the License for the specific language governing permissions and
          + * limitations under the License.
          + */
          +package com.opensymphony.xwork2.spring;
          +
          +import com.opensymphony.xwork2.util.ClassLoaderUtil;
          +import org.apache.commons.lang3.reflect.MethodUtils;
          +
          +import java.lang.reflect.Proxy;
          +
          +/**
          + * <code>SpringUtils</code>
          + * <p>
          + * Various utility methods dealing with spring framework
          + * </p>
          + *
          + */
          +public class SpringUtils {
          — End diff –

          `SpringUtils` doesn't sound good but I have no better name for now. Also it's the only case we have now so we can always refactor this code and introduce an interface with few implementation latter on.

          For future reference: it would be good to have a `ProxyAware` interface in the `core` with a default implementation (that does nothing) and then in the Spring Plugin provide a real implementation.

          Show
          githubbot ASF GitHub Bot added a comment - Github user lukaszlenart commented on a diff in the pull request: https://github.com/apache/struts/pull/135#discussion_r115664014 — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java — @@ -0,0 +1,89 @@ +/* + * Copyright 2017 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import org.apache.commons.lang3.reflect.MethodUtils; + +import java.lang.reflect.Proxy; + +/** + * <code>SpringUtils</code> + * <p> + * Various utility methods dealing with spring framework + * </p> + * + */ +public class SpringUtils { — End diff – `SpringUtils` doesn't sound good but I have no better name for now. Also it's the only case we have now so we can always refactor this code and introduce an interface with few implementation latter on. For future reference: it would be good to have a `ProxyAware` interface in the `core` with a default implementation (that does nothing) and then in the Spring Plugin provide a real implementation.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on a diff in the pull request:

          https://github.com/apache/struts/pull/135#discussion_r115767804

          — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java —
          @@ -0,0 +1,89 @@
          +/*
          + * Copyright 2017 The Apache Software Foundation.
          + *
          + * Licensed under the Apache License, Version 2.0 (the "License");
          + * you may not use this file except in compliance with the License.
          + * You may obtain a copy of the License at
          + *
          + * http://www.apache.org/licenses/LICENSE-2.0
          + *
          + * Unless required by applicable law or agreed to in writing, software
          + * distributed under the License is distributed on an "AS IS" BASIS,
          + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          + * See the License for the specific language governing permissions and
          + * limitations under the License.
          + */
          +package com.opensymphony.xwork2.spring;
          +
          +import com.opensymphony.xwork2.util.ClassLoaderUtil;
          +import org.apache.commons.lang3.reflect.MethodUtils;
          +
          +import java.lang.reflect.Proxy;
          +
          +/**
          + * <code>SpringUtils</code>
          + * <p>
          + * Various utility methods dealing with spring framework
          + * </p>
          + *
          + */
          +public class SpringUtils {
          — End diff –

          Thank you! Unfortunately I did not understand well. Do you mean that the user has to be careful to implement `ProxyAware` or inherit Spring Plugin's default implementation in his proxied actions? If so, there are two disadvantages, first he has to be careful about which actions may be proxied, and second he has to add Spring Plugin dependency or implement it manually.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on a diff in the pull request: https://github.com/apache/struts/pull/135#discussion_r115767804 — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java — @@ -0,0 +1,89 @@ +/* + * Copyright 2017 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import org.apache.commons.lang3.reflect.MethodUtils; + +import java.lang.reflect.Proxy; + +/** + * <code>SpringUtils</code> + * <p> + * Various utility methods dealing with spring framework + * </p> + * + */ +public class SpringUtils { — End diff – Thank you! Unfortunately I did not understand well. Do you mean that the user has to be careful to implement `ProxyAware` or inherit Spring Plugin's default implementation in his proxied actions? If so, there are two disadvantages, first he has to be careful about which actions may be proxied, and second he has to add Spring Plugin dependency or implement it manually.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user lukaszlenart commented on a diff in the pull request:

          https://github.com/apache/struts/pull/135#discussion_r115808166

          — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java —
          @@ -0,0 +1,89 @@
          +/*
          + * Copyright 2017 The Apache Software Foundation.
          + *
          + * Licensed under the Apache License, Version 2.0 (the "License");
          + * you may not use this file except in compliance with the License.
          + * You may obtain a copy of the License at
          + *
          + * http://www.apache.org/licenses/LICENSE-2.0
          + *
          + * Unless required by applicable law or agreed to in writing, software
          + * distributed under the License is distributed on an "AS IS" BASIS,
          + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          + * See the License for the specific language governing permissions and
          + * limitations under the License.
          + */
          +package com.opensymphony.xwork2.spring;
          +
          +import com.opensymphony.xwork2.util.ClassLoaderUtil;
          +import org.apache.commons.lang3.reflect.MethodUtils;
          +
          +import java.lang.reflect.Proxy;
          +
          +/**
          + * <code>SpringUtils</code>
          + * <p>
          + * Various utility methods dealing with spring framework
          + * </p>
          + *
          + */
          +public class SpringUtils {
          — End diff –

          no, no ... it was just for a future reference when we will want turn this into a bean

          Show
          githubbot ASF GitHub Bot added a comment - Github user lukaszlenart commented on a diff in the pull request: https://github.com/apache/struts/pull/135#discussion_r115808166 — Diff: core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java — @@ -0,0 +1,89 @@ +/* + * Copyright 2017 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import org.apache.commons.lang3.reflect.MethodUtils; + +import java.lang.reflect.Proxy; + +/** + * <code>SpringUtils</code> + * <p> + * Various utility methods dealing with spring framework + * </p> + * + */ +public class SpringUtils { — End diff – no, no ... it was just for a future reference when we will want turn this into a bean
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user yasserzamani commented on the issue:

          https://github.com/apache/struts/pull/135

          @lukaszlenart , I updated with @aleksandr-m reviews. I hope it is ready for merge if you pals agree.

          Show
          githubbot ASF GitHub Bot added a comment - Github user yasserzamani commented on the issue: https://github.com/apache/struts/pull/135 @lukaszlenart , I updated with @aleksandr-m reviews. I hope it is ready for merge if you pals agree.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user lukaszlenart commented on the issue:

          https://github.com/apache/struts/pull/135

          I think with can go ahead and merge this, @aleksandr-m any objections?

          Show
          githubbot ASF GitHub Bot added a comment - Github user lukaszlenart commented on the issue: https://github.com/apache/struts/pull/135 I think with can go ahead and merge this, @aleksandr-m any objections?
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user aleksandr-m commented on the issue:

          https://github.com/apache/struts/pull/135

          @lukaszlenart I think it is ok.

          Show
          githubbot ASF GitHub Bot added a comment - Github user aleksandr-m commented on the issue: https://github.com/apache/struts/pull/135 @lukaszlenart I think it is ok.
          Hide
          jira-bot ASF subversion and git services added a comment -

          Commit c2f2de06ce3c5545878a3b421fdde3ca5495d3cc in struts's branch refs/heads/master from Yasser Zamani
          [ https://git-wip-us.apache.org/repos/asf?p=struts.git;h=c2f2de0 ]

          WW-4105 Unwraps Spring proxy in actions chain

          Show
          jira-bot ASF subversion and git services added a comment - Commit c2f2de06ce3c5545878a3b421fdde3ca5495d3cc in struts's branch refs/heads/master from Yasser Zamani [ https://git-wip-us.apache.org/repos/asf?p=struts.git;h=c2f2de0 ] WW-4105 Unwraps Spring proxy in actions chain
          Hide
          jira-bot ASF subversion and git services added a comment -

          Commit 9a8b4f4ebcb3787bef76198a7374bb5dcb69908e in struts's branch refs/heads/master from Yasser Zamani
          [ https://git-wip-us.apache.org/repos/asf?p=struts.git;h=9a8b4f4 ]

          WW-4105 Removes SpringUtils to ProxyUtil

          Show
          jira-bot ASF subversion and git services added a comment - Commit 9a8b4f4ebcb3787bef76198a7374bb5dcb69908e in struts's branch refs/heads/master from Yasser Zamani [ https://git-wip-us.apache.org/repos/asf?p=struts.git;h=9a8b4f4 ] WW-4105 Removes SpringUtils to ProxyUtil
          Hide
          jira-bot ASF subversion and git services added a comment -

          Commit 8b862f7cb2eaa6289ec9b36e7dc4a47521fc3bca in struts's branch refs/heads/master from Lukasz Lenart
          [ https://git-wip-us.apache.org/repos/asf?p=struts.git;h=8b862f7 ]

          WW-4105 Adds support for Spring proxies when chaining actions

          Show
          jira-bot ASF subversion and git services added a comment - Commit 8b862f7cb2eaa6289ec9b36e7dc4a47521fc3bca in struts's branch refs/heads/master from Lukasz Lenart [ https://git-wip-us.apache.org/repos/asf?p=struts.git;h=8b862f7 ] WW-4105 Adds support for Spring proxies when chaining actions
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user asfgit closed the pull request at:

          https://github.com/apache/struts/pull/135

          Show
          githubbot ASF GitHub Bot added a comment - Github user asfgit closed the pull request at: https://github.com/apache/struts/pull/135
          Hide
          lukaszlenart Lukasz Lenart added a comment -

          PR got merged

          Show
          lukaszlenart Lukasz Lenart added a comment - PR got merged
          Hide
          hudson Hudson added a comment -

          SUCCESS: Integrated in Jenkins build Struts-JDK7-master #630 (See https://builds.apache.org/job/Struts-JDK7-master/630/)
          WW-4105 Unwraps Spring proxy in actions chain (yasser.zamani: rev c2f2de06ce3c5545878a3b421fdde3ca5495d3cc)

          • (add) core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java
          • (edit) core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java
          • (add) core/src/test/java/com/opensymphony/xwork2/TestSubBean.java
          • (edit) core/src/test/java/com/opensymphony/xwork2/spring/ActionsFromSpringTest.java
          • (edit) core/src/test/resources/com/opensymphony/xwork2/spring/actionContext-xwork.xml
          • (edit) core/src/test/resources/com/opensymphony/xwork2/spring/actionContext-spring.xml
          • (add) core/src/test/java/com/opensymphony/xwork2/spring/SpringUtilsTest.java
            WW-4105 Removes SpringUtils to ProxyUtil (yasser.zamani: rev 9a8b4f4ebcb3787bef76198a7374bb5dcb69908e)
          • (add) core/src/test/java/com/opensymphony/xwork2/spring/SpringProxyUtilTest.java
          • (add) core/src/main/java/com/opensymphony/xwork2/util/ProxyUtil.java
          • (delete) core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java
          • (edit) core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java
          • (delete) core/src/test/java/com/opensymphony/xwork2/spring/SpringUtilsTest.java
          Show
          hudson Hudson added a comment - SUCCESS: Integrated in Jenkins build Struts-JDK7-master #630 (See https://builds.apache.org/job/Struts-JDK7-master/630/ ) WW-4105 Unwraps Spring proxy in actions chain (yasser.zamani: rev c2f2de06ce3c5545878a3b421fdde3ca5495d3cc) (add) core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java (edit) core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java (add) core/src/test/java/com/opensymphony/xwork2/TestSubBean.java (edit) core/src/test/java/com/opensymphony/xwork2/spring/ActionsFromSpringTest.java (edit) core/src/test/resources/com/opensymphony/xwork2/spring/actionContext-xwork.xml (edit) core/src/test/resources/com/opensymphony/xwork2/spring/actionContext-spring.xml (add) core/src/test/java/com/opensymphony/xwork2/spring/SpringUtilsTest.java WW-4105 Removes SpringUtils to ProxyUtil (yasser.zamani: rev 9a8b4f4ebcb3787bef76198a7374bb5dcb69908e) (add) core/src/test/java/com/opensymphony/xwork2/spring/SpringProxyUtilTest.java (add) core/src/main/java/com/opensymphony/xwork2/util/ProxyUtil.java (delete) core/src/main/java/com/opensymphony/xwork2/spring/SpringUtils.java (edit) core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java (delete) core/src/test/java/com/opensymphony/xwork2/spring/SpringUtilsTest.java

            People

            • Assignee:
              Unassigned
              Reporter:
              zeroyet zhouyong
            • Votes:
              0 Vote for this issue
              Watchers:
              7 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development