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)