[ 
https://issues.apache.org/jira/browse/DIGESTER-180?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14257205#comment-14257205
 ] 

Barney Barumba edited comment on DIGESTER-180 at 12/24/14 11:42 AM:
--------------------------------------------------------------------

I think the problem is in the {{ObjectCreateRule.intercept}} method:

{code}
public Object intercept( Object obj, Method method, Object[] args, MethodProxy 
proxy )
    throws Throwable
{
    boolean hasDelegate = delegate != null;
    if ( !hasDelegate )
    {
        invocations.add( new RecordedInvocation( method, args ) );
    }
    if ( hasDelegate )
    {
        return proxy.invoke( delegate, args );
    }
    return proxy.invokeSuper( obj, args );
}
{code}

This records *all* intercepted method calls on the object being constructed, 
whereas it should probably only record the method calls invoked directly from 
the digester, and not those called internally within the object.

So when building the proxy object, the digester calls {{addWidget}} which in 
turn calls {{addWidgetInternal}}, but both of these method invocations are 
intercepted and recorded. So later in {{ObjectCreateRule.establishDelegate}} 
when all invocations are played back, both of these calls are repeated, when 
only the first should be.

Not sure of the best way to fix this, but hope it helps.


was (Author: baarney):
Just found something else which may be relevant... as above, if 
{{addWidgetIternal}} is {{public}} I see it get called twice, and if it is 
{{private}} then it is only called once and everything is ok. However, if I 
make it {{protected}} I see the following exception:

{code}
04:00:55 ERROR org.apache.commons.digester3.Digester: End event threw exception
java.lang.IllegalAccessException: Class 
org.apache.commons.digester3.ObjectCreateRule$DeferredConstructionCallback can 
not access a member of class Box with modifiers "protected"
        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.commons.digester3.ObjectCreateRule$DeferredConstructionCallback.establishDelegate(ObjectCreateRule.java:83)
        at 
org.apache.commons.digester3.ObjectCreateRule$ProxyManager.finalize(ObjectCreateRule.java:184)
        at 
org.apache.commons.digester3.ObjectCreateRule.end(ObjectCreateRule.java:388)
        at org.apache.commons.digester3.Digester.endElement(Digester.java:1128)
{code}

> Digester calls invalid method when using proxy ObjectCreate rule
> ----------------------------------------------------------------
>
>                 Key: DIGESTER-180
>                 URL: https://issues.apache.org/jira/browse/DIGESTER-180
>             Project: Commons Digester
>          Issue Type: Bug
>    Affects Versions: 3.2
>         Environment: Linux x_86_64, JDK 1.7.0_65
>            Reporter: Barney Barumba
>         Attachments: Box.java
>
>
> Hi, I've encountered some strange behaviour when using the new proxy object 
> create: the digester appears to call a method that is never mentioned in the 
> digester rules! I've simplified it as much as I can to the following (full, 
> runnable code attached):
> A simple box of widgets:
> {code}
>   private final String id;
>   private final Set<String> widgetIds = new HashSet<>();
>   
>   public Box(String id) {
>     System.out.println("Box: id=" + id);
>     this.id = id;
>   }
>   
>   public void addWidget(String widgetId) {
>     System.out.println("addWidget: id=" + id + ", wid=" + widgetId);
>     addWidgetInternal(widgetId);
>   }
>   
>   public void addWidgetInternal(String widgetId) {
>     System.out.println("addWidgetInternal: id=" + id + ", wid=" + widgetId);
>     if (widgetIds.contains(widgetId)) {
>       System.err.println("*** box already contains widget " + widgetId);
>     } else {
>       widgetIds.add(widgetId);
>     }
>   }
> {code}
> The source XML is fairly straightforward:
> {code}
> <box id='b01'>
>   <widget wid='w01'>Widget 1</widget>
> </box>
> {code}
> as are the rules:
> {code}
>   forPattern("box")
>       .createObject().ofType(Box.class).usingConstructor(String.class)
>       .usingDefaultConstructorArguments("")
>       .then().callParam().fromAttribute("id").ofIndex(0);
>     
>   forPattern("box/widget")
>       .callMethod("addWidget")
>       .withParamCount(1)
>       .then().callParam().fromAttribute("wid").ofIndex(0);
> {code}
> The key point here is that the rules only ever invoke {{addWidget}}, and this 
> calls {{addWidgetInternal}}. However, when I run this, {{addWidgetInternal}} 
> gets called twice, the second time directly from the digester, and I get the 
> following output:
> {code}
> Box: id=
> addWidget: id=, wid=w01
> addWidgetInternal: id=, wid=w01
> Box: id=b01
> addWidget: id=b01, wid=w01
> addWidgetInternal: id=b01, wid=w01
> addWidgetInternal: id=b01, wid=w01
> *** box already contains widget w01
> {code}
> I'm guessing that this is connected with the proxy code because I can change 
> any number of things to make it work:
> * Make {{addWidgetInternal}} private;
> * Call {{addWidgetInternal}} directly from the digester rules.
> * Use a custom object create rule instead (see attached code).



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to