<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yannick Ebongue</title>
    <description>The latest articles on DEV Community by Yannick Ebongue (@yannickebongue).</description>
    <link>https://dev.to/yannickebongue</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4160006%2Fd2f8a802-e917-4a7f-b447-50f269834ff3.png</url>
      <title>DEV Community: Yannick Ebongue</title>
      <link>https://dev.to/yannickebongue</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yannickebongue"/>
    <language>en</language>
    <item>
      <title>How We Solved Groovy's MissingMethodException inside Gradle Runtime Task Proxies</title>
      <dc:creator>Yannick Ebongue</dc:creator>
      <pubDate>Wed, 07 Oct 2026 14:06:32 +0000</pubDate>
      <link>https://dev.to/yannickebongue/how-we-solved-groovys-missingmethodexception-inside-gradle-runtime-task-proxies-gml</link>
      <guid>https://dev.to/yannickebongue/how-we-solved-groovys-missingmethodexception-inside-gradle-runtime-task-proxies-gml</guid>
      <description>&lt;p&gt;If you’ve ever authored a custom Gradle plugin that handles dynamic file structures using Groovy's &lt;code&gt;MarkupBuilder&lt;/code&gt; or &lt;code&gt;XmlParser&lt;/code&gt;, you have likely encountered a ghost in the machine: the dreaded &lt;strong&gt;&lt;code&gt;MissingMethodException&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It usually happens when you are refining task settings or running complex incremental build tests. Suddenly, code that passed unit tests perfectly blows up in a real-world multi-module build execution pass. &lt;/p&gt;

&lt;p&gt;Here is the deep engineering breakdown of how we encountered a hidden runtime proxy trap inside the &lt;strong&gt;Gradle Task Decoration Engine&lt;/strong&gt; while building &lt;strong&gt;jPersist v1.4.1&lt;/strong&gt;, and the design pattern we used to fix it permanently.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Target Architecture: Dynamic XML Descriptor Management
&lt;/h2&gt;

&lt;p&gt;In enterprise Jakarta Persistence (JPA) environments, managing &lt;code&gt;persistence.xml&lt;/code&gt; files in large multi-module projects is a known headache. Our plugin, &lt;code&gt;io.github.jpersist.jpa&lt;/code&gt;, solves this by automating entity class discovery via high-speed ASM bytecode scanning and generating or merging the final descriptors cleanly on the fly.&lt;/p&gt;

&lt;p&gt;To keep configuration clean, we leveraged Groovy's idiomatic &lt;code&gt;MarkupBuilder&lt;/code&gt; inside our custom task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProcessPersistenceDescriptor&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;DefaultTask&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Gradle lazy property bindings...&lt;/span&gt;

    &lt;span class="nd"&gt;@TaskAction&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hasTemplate&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;StringWriter&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;StringWriter&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;xml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;groovy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MarkupBuilder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;persistence&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;version:&lt;/span&gt; &lt;span class="s2"&gt;"3.1"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// A closure manipulating elements dynamically&lt;/span&gt;
            &lt;span class="s2"&gt;"persistence-unit"&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"app-unit"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"org.hibernate.jpa.HibernatePersistenceProvider"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks elegant, passes isolated tests, and works seamlessly—until a downstream consumer tries to mutate plugin extensions or apply complex custom build profiles. Suddenly, the build crashes with a cryptic runtime trace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Caused by: org.gradle.internal.metaobject.AbstractDynamicObject$CustomMessageMissingMethodException: 
Could not find method generate() for arguments [...] on task ':app:processPersistenceDescriptor' 
of type persist.jakarta.gradle.task.ProcessPersistenceDescriptor_Decorated.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait, &lt;code&gt;generate()&lt;/code&gt; is a private method clearly defined right inside the task class. How can it be "missing"? And what on earth is &lt;code&gt;ProcessPersistenceDescriptor_Decorated&lt;/code&gt;?&lt;/p&gt;




&lt;h2&gt;
  
  
  The Trap: Gradle's Decorated Runtime Proxy Object
&lt;/h2&gt;

&lt;p&gt;To enforce lazy evaluation, property tracking, input validation, and incremental build snapshots caching, &lt;strong&gt;Gradle does not execute your raw task class directly.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Instead, on startup, Gradle’s internal object factory dynamically subclasses your task at runtime via bytecode generation, creating a wrapper proxy matching the pattern &lt;code&gt;${YourTaskClass}_Decorated&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  [ Your Task Class ]  &amp;lt;--- You wrote this
           ▲
           │ (Inherits &amp;amp; Overrides)
  [ YourTaskClass_Decorated ]  &amp;lt;--- Gradle executes this at runtime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This decorated proxy object intercepts all standard Groovy method dispatch mechanisms (&lt;code&gt;invokeMethod&lt;/code&gt;, &lt;code&gt;methodMissing&lt;/code&gt;, &lt;code&gt;propertyMissing&lt;/code&gt;) to perform its internal dependency tracking and lifecycle magic. &lt;/p&gt;

&lt;p&gt;Here is where the collision happens:&lt;br&gt;
Groovy closures (like the code block inside &lt;code&gt;xml.persistence { ... }&lt;/code&gt;) inherit the surrounding method instance as their default execution &lt;code&gt;owner&lt;/code&gt; and &lt;code&gt;delegate&lt;/code&gt;. When &lt;code&gt;MarkupBuilder&lt;/code&gt; evaluates an abstract tag entry line like &lt;code&gt;provider(...)&lt;/code&gt;, Groovy's dynamic dispatcher starts sweeping up the delegation hierarchy to resolve the call.&lt;/p&gt;

&lt;p&gt;Instead of hitting the &lt;code&gt;MarkupBuilder&lt;/code&gt; configuration graph safely, Gradle's &lt;strong&gt;public decorated proxy wrapper interceptor&lt;/strong&gt; flags the expression. Because the proxy exposes open-ended method definitions, it tricks Groovy into bypassing the builder context completely. It routes the evaluation right back into the task object instance, leading to an immediate parameters signature mismatch and a full task explosion.&lt;/p&gt;

&lt;p&gt;Marking your methods &lt;code&gt;private&lt;/code&gt; doesn't stop this, because the generated runtime proxy opens up visibility entry points to monitor task state transitions.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Masterclass Solution: The Static Processor Isolation Strategy
&lt;/h2&gt;

&lt;p&gt;To permanently insulate dynamic DSL blocks and XML parser closures from Gradle's runtime proxy manipulation, we must &lt;strong&gt;completely break the object instance chain.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If an execution closure doesn't carry a reference to a parent class object instance, Gradle's proxy wrapper has nothing to attach to. We achieved this by restructuring our plugin tasks around the &lt;strong&gt;Strategy Design Pattern&lt;/strong&gt; and encapsulating the execution logic within a &lt;strong&gt;purely static evaluation utility&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here is the bulletproof architecture shipped in &lt;strong&gt;jPersist v1.4.1&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="nd"&gt;@DisableCachingByDefault&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;because&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Process overwrite persistence.xml in place"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProcessPersistenceDescriptor&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;DefaultTask&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Task parameters handles strictly isolated to lazy Gradle Property wrappers&lt;/span&gt;
    &lt;span class="nd"&gt;@Input&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="n"&gt;Property&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getXmlVersion&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="nd"&gt;@OutputFile&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="n"&gt;RegularFileProperty&lt;/span&gt; &lt;span class="n"&gt;getDestinationFile&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;

    &lt;span class="nd"&gt;@TaskAction&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Unpack properties securely inside the safe @TaskAction boundary&lt;/span&gt;
        &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;destinationFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;asFile&lt;/span&gt;
        &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;versionStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;xmlVersion&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;// 1. Resolve processing characteristics via a Strategy Factory Registry&lt;/span&gt;
        &lt;span class="n"&gt;JpaVersionStrategyRegistry&lt;/span&gt; &lt;span class="n"&gt;strategyConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JpaVersionStrategyRegistry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;versionStr&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// 2. PASS TO AN ISOLATED STATIC LAYER&lt;/span&gt;
        &lt;span class="c1"&gt;// This cuts off the parent instance reference, bypassing the proxy wrapper entirely!&lt;/span&gt;
        &lt;span class="n"&gt;strategyConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delegate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;versionStr&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And inside our decoupled, static execution strategy delegate layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JPA30DescriptorProcessorDelegate&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="n"&gt;DescriptorProcessorDelegate&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;xmlVersion&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// All closures here evaluate inside a safe, predictable context&lt;/span&gt;
        &lt;span class="n"&gt;StringWriter&lt;/span&gt; &lt;span class="n"&gt;rawXmlWriter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;StringWriter&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;MarkupBuilder&lt;/span&gt; &lt;span class="n"&gt;xml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MarkupBuilder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rawXmlWriter&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;persistence&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;version:&lt;/span&gt; &lt;span class="n"&gt;xmlVersion&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Groovy now resolves these paths directly via MarkupBuilder &lt;/span&gt;
            &lt;span class="c1"&gt;// with ZERO risk of proxy interception!&lt;/span&gt;
            &lt;span class="s2"&gt;"persistence-unit"&lt;/span&gt;&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="nl"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"secure-unit"&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"org.hibernate.jpa.HibernatePersistenceProvider"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;writeOutputFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rawXmlWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Engineering Takeaway
&lt;/h2&gt;

&lt;p&gt;By unpacking raw task properties inside the &lt;code&gt;@TaskAction&lt;/code&gt; boundary and passing them straight as primitives or decoupled objects into an independent &lt;strong&gt;&lt;code&gt;static class&lt;/code&gt; block&lt;/strong&gt;, we successfully cut off the parent instance reference. &lt;/p&gt;

&lt;p&gt;When Groovy looks for method resolution paths inside the &lt;code&gt;MarkupBuilder&lt;/code&gt; boundaries, it no longer crosses paths with &lt;code&gt;ProcessPersistenceDescriptor_Decorated&lt;/code&gt;. The closures run inside a completely clean environment, allowing enterprise builds to run smoothly across any configuration cache change pass.&lt;/p&gt;

&lt;p&gt;If you are building custom Gradle tooling that relies on nested builders, dynamic closures, or heavy XML transformations, save yourself days of debugging: &lt;strong&gt;Keep your tasks strictly focused on tracking input/output properties, and delegate the execution out to static processors.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  🌐 Learn More &amp;amp; Support Independence
&lt;/h3&gt;

&lt;p&gt;This architecture is part of &lt;strong&gt;jPersist&lt;/strong&gt;, an open-source, configuration-cache-compliant Gradle plugin suite that automates descriptor management, static metamodel generation, and compile-time static weaving for Hibernate and EclipseLink ecosystems.&lt;/p&gt;

&lt;p&gt;Check out the code, view runnable enterprise multi-module specs, or drop a star on GitHub:&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://github.com/jpersist/persistence" rel="noopener noreferrer"&gt;GitHub - jpersist/persistence&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If this deep-dive saved you debugging hours on your custom build pipelines, consider checking out our &lt;a href="https://github.com/sponsors/jpersist" rel="noopener noreferrer"&gt;GitHub Sponsors Tiers Profile&lt;/a&gt; to back the project's long-term independence!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gradle</category>
      <category>java</category>
      <category>groovy</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
