[
https://issues.apache.org/jira/browse/ARIES-1342?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Declan Cox updated ARIES-1342:
------------------------------
Description:
I have a simple type hierarchy with a base interface and an extending interface
with method overriding (covariant return types). A service implements the
derived interface (ColumnDAO - see attached test case). The attached test case
illustrates the scenario. In certain situations AriesProxy Impl (more
specifically the InterfaceCombiningClassAdapter) fails to properly synthesize
the proxy code. In particular it is a combination of the lexical naming of the
classes in the hierarchy and Java 8 method access flags that does it. The
naming of the classes determines the order in which they are processed since
the ProxyClassLoader receives a sorted set of classes when building the proxy.
If that order happens to be such that the types are processed in hierarchy
order starting with the base type, then all is cool. If not then trouble
arises.
Why ? Well if a more derived type is processed then it instruments base methods
which are marked (in Java 8) with Synthetic and Bridge access flags. In this
case the {{visitMethod()}} in {{AbstractWovenProxyAdapter}} does not generate
any code but records the fact that this method has been visited. No code is
generated due to the logic implemented here and the way Java 8 generates access
flags in this case.
In the test case running javap -verbose on the derived type yields the
following (note the base type is named ZanyDAO to force the lexical ordering
and thus the error) :
{noformat}
public abstract org.deklanowski.aries.dao.ColumnBatch<R, C, V> prepareBatch();
flags: ACC_PUBLIC, ACC_ABSTRACT
Signature: #9 //
()Lorg/deklanowski/aries/dao/ColumnBatch<TR;TC;TV;>;
public abstract org.deklanowski.aries.dao.ColumnQuery<R, C, V> createQuery();
flags: ACC_PUBLIC, ACC_ABSTRACT
Signature: #12 //
()Lorg/deklanowski/aries/dao/ColumnQuery<TR;TC;TV;>;
public org.deklanowski.aries.dao.Batch prepareBatch();
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokeinterface #1, 1 // InterfaceMethod
prepareBatch:()Lorg/deklanowski/aries/dao/ColumnBatch;
6: areturn
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 this Lorg/deklanowski/aries/dao/ColumnDAO;
LocalVariableTypeTable:
Start Length Slot Name Signature
0 7 0 this
Lorg/deklanowski/aries/dao/ColumnDAO<TR;TC;TV;>;
public org.deklanowski.aries.dao.Query createQuery();
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokeinterface #2, 1 // InterfaceMethod
createQuery:()Lorg/deklanowski/aries/dao/ColumnQuery;
6: areturn
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 this Lorg/deklanowski/aries/dao/ColumnDAO;
LocalVariableTypeTable:
Start Length Slot Name Signature
0 7 0 this
Lorg/deklanowski/aries/dao/ColumnDAO<TR;TC;TV;>;
{noformat}
The logic in the aforementioned {{AbstractWovenProxyAdapter.visitMethod()}} on
line 341 is as follows:
{noformat}
if ((access & (ACC_STATIC | ACC_PRIVATE | ACC_SYNTHETIC
| ACC_NATIVE | ACC_BRIDGE)) == 0 && !!!name.equals("<init>") &&
!!!name.equals("<clinit>")) {
<snip>
{noformat}
The if statement evaluates to false and no code is generated though the method
descriptions are recorded as having been visited.
was:
I have a simple type hierarchy with a base interface and an extending interface
with method overriding (covariant return types). A service implements the
derived interface (ColumnDAO - see attached test case). The attached test case
illustrates the scenario. In certain situations AriesProxy Impl (more
specifically the InterfaceCombiningClassAdapter) fails to properly synthesize
the proxy code. In particular it is a combination of the lexical naming of the
classes in the hierarchy and Java 8 method access flags that does it. The
naming of the classes determines the order in which they are processed since
the ProxyClassLoader receives a sorted set of classes when building the proxy.
If that order happens to be such that the types are processed in hierarchy
order starting with the base type, then all is cool. If not then trouble
arises.
Why ? Well if a more derived type is processed then it instruments base methods
which are marked (in Java 8) with Synthetic and Bridge access flags. In this
case the {{visitMethod()}} in {{AbstractWovenProxyAdapter}} does not generate
any code but records the fact that this method has been visited. No code is
generated due to the logic implemented here and the way Java 8 generates access
flags in this case.
In the test case running javap -verbose on the derived type yields the
following (note the base type is named ZanyDAO to force the lexical ordering
and thus the error) :
{{
public abstract org.deklanowski.aries.dao.ColumnBatch<R, C, V> prepareBatch();
flags: ACC_PUBLIC, ACC_ABSTRACT
Signature: #9 //
()Lorg/deklanowski/aries/dao/ColumnBatch<TR;TC;TV;>;
public abstract org.deklanowski.aries.dao.ColumnQuery<R, C, V> createQuery();
flags: ACC_PUBLIC, ACC_ABSTRACT
Signature: #12 //
()Lorg/deklanowski/aries/dao/ColumnQuery<TR;TC;TV;>;
public org.deklanowski.aries.dao.Batch prepareBatch();
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokeinterface #1, 1 // InterfaceMethod
prepareBatch:()Lorg/deklanowski/aries/dao/ColumnBatch;
6: areturn
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 this Lorg/deklanowski/aries/dao/ColumnDAO;
LocalVariableTypeTable:
Start Length Slot Name Signature
0 7 0 this
Lorg/deklanowski/aries/dao/ColumnDAO<TR;TC;TV;>;
public org.deklanowski.aries.dao.Query createQuery();
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokeinterface #2, 1 // InterfaceMethod
createQuery:()Lorg/deklanowski/aries/dao/ColumnQuery;
6: areturn
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 this Lorg/deklanowski/aries/dao/ColumnDAO;
LocalVariableTypeTable:
Start Length Slot Name Signature
0 7 0 this
Lorg/deklanowski/aries/dao/ColumnDAO<TR;TC;TV;>;
}}
The logic in the aforementioned {{AbstractWovenProxyAdapter.visitMethod()}} on
line 341 is as follows:
{{
if ((access & (ACC_STATIC | ACC_PRIVATE | ACC_SYNTHETIC
| ACC_NATIVE | ACC_BRIDGE)) == 0 && !!!name.equals("<init>") &&
!!!name.equals("<clinit>")) {
}}
The if statement evaluates to false and no code is generated though the method
descriptions are recorded as having been visited.
> Aries Proxy Impl fails to proxy covariant type hierarchy in Java 8
> ------------------------------------------------------------------
>
> Key: ARIES-1342
> URL: https://issues.apache.org/jira/browse/ARIES-1342
> Project: Aries
> Issue Type: Bug
> Components: Blueprint
> Affects Versions: proxy-impl-1.0.3
> Environment: Karaf 3.0.3/Karaf 4.0.0, JDK 1.8.0_u45
> Reporter: Declan Cox
> Priority: Critical
> Labels: proxy-impl-1.0.4
> Attachments: aries-proxy-issue.rar
>
>
> I have a simple type hierarchy with a base interface and an extending
> interface with method overriding (covariant return types). A service
> implements the derived interface (ColumnDAO - see attached test case). The
> attached test case illustrates the scenario. In certain situations AriesProxy
> Impl (more specifically the InterfaceCombiningClassAdapter) fails to properly
> synthesize the proxy code. In particular it is a combination of the lexical
> naming of the classes in the hierarchy and Java 8 method access flags that
> does it. The naming of the classes determines the order in which they are
> processed since the ProxyClassLoader receives a sorted set of classes when
> building the proxy. If that order happens to be such that the types are
> processed in hierarchy order starting with the base type, then all is cool.
> If not then trouble arises.
> Why ? Well if a more derived type is processed then it instruments base
> methods which are marked (in Java 8) with Synthetic and Bridge access flags.
> In this case the {{visitMethod()}} in {{AbstractWovenProxyAdapter}} does not
> generate any code but records the fact that this method has been visited. No
> code is generated due to the logic implemented here and the way Java 8
> generates access flags in this case.
> In the test case running javap -verbose on the derived type yields the
> following (note the base type is named ZanyDAO to force the lexical ordering
> and thus the error) :
> {noformat}
> public abstract org.deklanowski.aries.dao.ColumnBatch<R, C, V> prepareBatch();
> flags: ACC_PUBLIC, ACC_ABSTRACT
> Signature: #9 //
> ()Lorg/deklanowski/aries/dao/ColumnBatch<TR;TC;TV;>;
> public abstract org.deklanowski.aries.dao.ColumnQuery<R, C, V>
> createQuery();
> flags: ACC_PUBLIC, ACC_ABSTRACT
> Signature: #12 //
> ()Lorg/deklanowski/aries/dao/ColumnQuery<TR;TC;TV;>;
> public org.deklanowski.aries.dao.Batch prepareBatch();
> flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
> Code:
> stack=1, locals=1, args_size=1
> 0: aload_0
> 1: invokeinterface #1, 1 // InterfaceMethod
> prepareBatch:()Lorg/deklanowski/aries/dao/ColumnBatch;
> 6: areturn
> LineNumberTable:
> line 3: 0
> LocalVariableTable:
> Start Length Slot Name Signature
> 0 7 0 this Lorg/deklanowski/aries/dao/ColumnDAO;
> LocalVariableTypeTable:
> Start Length Slot Name Signature
> 0 7 0 this
> Lorg/deklanowski/aries/dao/ColumnDAO<TR;TC;TV;>;
> public org.deklanowski.aries.dao.Query createQuery();
> flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
> Code:
> stack=1, locals=1, args_size=1
> 0: aload_0
> 1: invokeinterface #2, 1 // InterfaceMethod
> createQuery:()Lorg/deklanowski/aries/dao/ColumnQuery;
> 6: areturn
> LineNumberTable:
> line 3: 0
> LocalVariableTable:
> Start Length Slot Name Signature
> 0 7 0 this Lorg/deklanowski/aries/dao/ColumnDAO;
> LocalVariableTypeTable:
> Start Length Slot Name Signature
> 0 7 0 this
> Lorg/deklanowski/aries/dao/ColumnDAO<TR;TC;TV;>;
> {noformat}
> The logic in the aforementioned {{AbstractWovenProxyAdapter.visitMethod()}}
> on line 341 is as follows:
> {noformat}
> if ((access & (ACC_STATIC | ACC_PRIVATE | ACC_SYNTHETIC
> | ACC_NATIVE | ACC_BRIDGE)) == 0 && !!!name.equals("<init>") &&
> !!!name.equals("<clinit>")) {
> <snip>
> {noformat}
> The if statement evaluates to false and no code is generated though the
> method descriptions are recorded as having been visited.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)