Good morning,
It appears that using JAXRSClientFactoryBean to create proxy-beans for JAX-RS 
webservices from within a TomEE 8.x container triggers a rather severe memory 
leak via Johnzon's JSON-B provider's CDI integration in TomEE 8.x (I did not 
test 9.x).

Specifically, if JAXRSClientFactoryBean is used while TomEEJsonbProvider (or 
JsonbJaxrsProvider) is on the OpenEJB JAX-RS JSON providers list (either the 
hard-coded default, or via 'openejb.jaxrs.jsonProviders'), then each call to 
JAXRSClientFactoryBean.create() will cause a new JohnzonJsonb object to be 
created and tracked by JohnzonCdiExtension.  For example, the following code is 
sufficient to trigger the issue if placed within a servlet class' doGet():
    JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
    bean.setServiceClass(IJaxrsWebservice.class);
    bean.setAddress(http://127.0.0.1:8080/reproducer);

    final IJaxrsWebservice proxy = bean.create(IJaxrsWebservice.class);

I have a sample project that includes this code and a mock JAX-RS webservice, 
reproducing the issue; a copy of this is available in this GitHub repo: 
https://github.com/deberhar/TomeeJohnzonBugReproducer.  If I repeatedly call 
the servlet, I can exhaust a 1GB application heap in ~4-6k GETs to the servlet 
-- the server reports OutOfMemoryErrors, and a heap dump shows 924MB retained 
by the JohnzonCdiExtension.  If it would be helpful, I can provide a copy of 
this project (what's the best way to do so?).

[Text  Description automatically generated]

I believe the underlying cause is described in this Johnzon bug report: 
https://issues.apache.org/jira/browse/JOHNZON-161.  However, it seems the 
Johnzon developers believe their CDI integration is behaving as expected, and 
that it is the responsibility of the integrating container to cache and re-use 
Jsonb instances, writing, in part:
> Hi skay, first of all it is a bug in your application so best is to fix your 
> coding style. Now you have a workaround: set johnzon.skip-cdi=true or 
> johnzon.cdi.activated=false in the jsonbconfig properties or set property 
> johnzon.factory to new SimpleJohnzonAdapterFactory().
> Side note: in terms of performance, recreating Jsonb instances looses all 
> caching and redo all the reflection so should be slow so in any case I 
> recommend you to change the pattern you have (it is true for jackson too btw)

It appears the Meecrowave developers made changes in their source code to 
prevent this leak via Johnzon's JsonbJaxrsProvider's CDI integration when used 
with CXF; see https://issues.apache.org/jira/browse/MEECROWAVE-104 or 
https://github.com/apache/openwebbeans-meecrowave/commit/eafd5b6eda81471c4abd61297a2455b2bca0a013.
For our organization's use of TomEE, we've been able to hack around this issue 
by subclassing TomEEJsonbProvider to set johnzon.cdi.activated=false, and then 
overriding the default provider list via openejb.jaxrs.jsonProviders.  However, 
this is likely not a proper solution.

What's the best way forward to addressing this properly?



Thank you,
David Eberhart
NYS Unified Court System
Office of Court Administration
Division of Technology and Court Research

Reply via email to