You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@openwebbeans.apache.org by "Alexander Zapletal (JIRA)" <ji...@apache.org> on 2018/03/01 16:55:00 UTC
[jira] [Updated] (OWB-1234) generic classes are not correctly
proxied when bridge methods are involved
[ https://issues.apache.org/jira/browse/OWB-1234?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Alexander Zapletal updated OWB-1234:
------------------------------------
Description:
Proxies generated by _NormalScopeProxyFactory_ do not contain (overriding) proxy methods for bridge methods, because bridge methods are generally ignored by the proxy generation, see _AbstractProxyFactory.unproxyableMethod()_ and _ClassUtil.addNonPrivateMethods()_ .
(See also OWB-923)
But this can lead to wrong proxies:
{code:java}
interface Contract {
void doIt(Integer param);
}
{code}
{code:java}
public class BaseBean<T extends Number> {
public void doIt(T param) {
}
}
{code}
{code:java}
@ApplicationScoped
public class MyBean extends BaseBean<Integer> implements Contract {
}
{code}
When compiling this code the compiler performs type erasure and needs to generate a bridge method. The generated byte code corresponds (roughly) to the following code:
{code:java}
public class BaseBean {
public void doIt(Number param) {
}
}
{code}
{code:java}
public class MyBean {
// bridge method!
public void doIt(Integer param) {
super.doIt(param);
}
}
{code}
_NormalScopeProxyFactory_ generates a proxy class that (roughly) corresponds to the following code:
{code:java}
public class MyBean$$OwbNormalScopeProxy extends MyBean {
public void doIt(Number var1) {
((MyBean)this.owbContextualInstanceProvider.get()).doIt(var1);
}
}
{code}
But when we now call, for instance, _doIt(4711)_ on an injected instance of _Contract_ , we actually call _MyBean.doIt(Integer)_ and thereby we bypass the proxy!
{code:java}
@Inject Contract handler;
handler.doIt(4711)
{code}
Reason: When _NormalScopeProxyFactory_ generated the proxy for _MyBean,_ it found the following two methods (amongst others):
{code:java}
void doIt(Number var1) // inherited from BaseBean
void doIt(Integer var1) // bridge method
{code}
Since _NormalScopeProxyFactory_ ignores bridge methods, it only generated a proxy method for _doIt(Number)_ . This method *overloads* _MyBean.doIt(Integer)_ , it does not *override* it. So, _handler.doIt(4711)_ actually calls _MyBean.doIt(Integer)_ .
*IMPORTANT NOTE:* There is a quite simple workaround for this problem: Just implement the bridge method yourself. I.e. in the example above use the following implementation
{code:java}
@ApplicationScoped
public class MyBean extends BaseBean<Integer> implements Contract {
@Override
public void doIt(Integer param) {
super.doIt(param);
}
}
{code}
Now, the method _doIt(Integer)_ is not a bridge method anymore and _NormalScopeProxyFactory_ will generate a proxy method for it.
was:
The proxy generated by _NormalScopeProxyFactory_ does not contain (overriding) proxy methods for bridge methods, because brdige methods are generally ignored by the proxy generation, see _AbstractProxyFactory.unproxyableMethod()_ and _ClassUtil.addNonPrivateMethods()_ .
(See also OWP-923)
But this can lead to wrong proxies:
{code:java}
interface Contract {
void doIt(Integer param);
}
{code}
{code:java}
public class BaseBean<T extends Number> {
public void doIt(T param) {
}
}
{code}
{code:java}
@ApplicationScoped
public class MyBean extends BaseBean<Integer> implements Contract {
}
{code}
When compiling this code the compiler performs type erasure and needs to generate a bridge method. The generated byte code corresponds (roughly) to the following code:
{code:java}
public class BaseBean {
public void doIt(Number param) {
}
}
{code}
{code:java}
public class MyBean {
// bridge method!
public void doIt(Integer param) {
super.doIt(param);
}
}
{code}
_NormalScopeProxyFactory_ generates a proxy class that (roughly) corresponds to the following code:
{code:java}
public class MyBean$$OwbNormalScopeProxy extends MyBean {
public void doIt(Number var1) {
((MyBean)this.owbContextualInstanceProvider.get()).doIt(var1);
}
}
{code}
But when we now call, for instance, _doIt(4711)_ on an injected instance of _Contract_ , we actually call _MyBean.doIt(Integer)_ and thereby we bypass the proxy!
{code:java}
@Inject Contract handler;
handler.doIt(4711)
{code}
Reason: When _NormalScopeProxyFactory_ generated the proxy for _MyBean,_ it found the following two methods (amongst others):
{code:java}
void doIt(Number var1) // inherited from BaseBean
void doIt(Integer var1) // bridge method
{code}
Since _NormalScopeProxyFactory_ ignores bridge methods, it only generated a proxy method for _doIt(Number)_ . This method *overloads* _MyBean.doIt(Integer)_ , it does not *override* it. So, _handler.doIt(4711)_ actually calls _MyBean.doIt(Integer)_ .
*IMPORTANT NOTE:* There is a quite simple workaround for this problem: Just implement the bridge method yourself. I.e. in the example above use the following implementation
{code:java}
@ApplicationScoped
public class MyBean extends BaseBean<Integer> implements Contract {
@Override
public void doIt(Integer param) {
super.doIt(param);
}
}
{code}
Now, the method _doIt(Integer)_ is not a bridge method anymore and _NormalScopeProxyFactory_ will generate a proxy method for it.
> generic classes are not correctly proxied when bridge methods are involved
> --------------------------------------------------------------------------
>
> Key: OWB-1234
> URL: https://issues.apache.org/jira/browse/OWB-1234
> Project: OpenWebBeans
> Issue Type: Bug
> Components: Interceptor and Decorators
> Affects Versions: 2.0.4
> Reporter: Alexander Zapletal
> Priority: Major
>
> Proxies generated by _NormalScopeProxyFactory_ do not contain (overriding) proxy methods for bridge methods, because bridge methods are generally ignored by the proxy generation, see _AbstractProxyFactory.unproxyableMethod()_ and _ClassUtil.addNonPrivateMethods()_ .
> (See also OWB-923)
> But this can lead to wrong proxies:
> {code:java}
> interface Contract {
> void doIt(Integer param);
> }
> {code}
> {code:java}
> public class BaseBean<T extends Number> {
> public void doIt(T param) {
> }
> }
> {code}
> {code:java}
> @ApplicationScoped
> public class MyBean extends BaseBean<Integer> implements Contract {
> }
> {code}
> When compiling this code the compiler performs type erasure and needs to generate a bridge method. The generated byte code corresponds (roughly) to the following code:
> {code:java}
> public class BaseBean {
> public void doIt(Number param) {
> }
> }
> {code}
> {code:java}
> public class MyBean {
> // bridge method!
> public void doIt(Integer param) {
> super.doIt(param);
> }
> }
> {code}
> _NormalScopeProxyFactory_ generates a proxy class that (roughly) corresponds to the following code:
> {code:java}
> public class MyBean$$OwbNormalScopeProxy extends MyBean {
>
> public void doIt(Number var1) {
> ((MyBean)this.owbContextualInstanceProvider.get()).doIt(var1);
> }
> }
> {code}
> But when we now call, for instance, _doIt(4711)_ on an injected instance of _Contract_ , we actually call _MyBean.doIt(Integer)_ and thereby we bypass the proxy!
> {code:java}
> @Inject Contract handler;
> handler.doIt(4711)
> {code}
> Reason: When _NormalScopeProxyFactory_ generated the proxy for _MyBean,_ it found the following two methods (amongst others):
> {code:java}
> void doIt(Number var1) // inherited from BaseBean
> void doIt(Integer var1) // bridge method
> {code}
> Since _NormalScopeProxyFactory_ ignores bridge methods, it only generated a proxy method for _doIt(Number)_ . This method *overloads* _MyBean.doIt(Integer)_ , it does not *override* it. So, _handler.doIt(4711)_ actually calls _MyBean.doIt(Integer)_ .
>
> *IMPORTANT NOTE:* There is a quite simple workaround for this problem: Just implement the bridge method yourself. I.e. in the example above use the following implementation
> {code:java}
> @ApplicationScoped
> public class MyBean extends BaseBean<Integer> implements Contract {
> @Override
> public void doIt(Integer param) {
> super.doIt(param);
> }
> }
> {code}
> Now, the method _doIt(Integer)_ is not a bridge method anymore and _NormalScopeProxyFactory_ will generate a proxy method for it.
--
This message was sent by Atlassian JIRA
(v7.6.3#76005)