Backend
XML Configuration Mode: Decoupling Your API Catalog from Business Code
paohaijiao DEV Community
1 views
Annotation mode keeps requests close to Java, but large integrations raise a fair question: do I want a wall of curl strings inside my service interfaces? JQuickCurl's XML mode answers with a firm no — you store every API definition in a separate XML file, and the business layer only sees plain Java interfaces with no annotations at all. This is the classic "declarative client" split: contract in configuration, behavior in code.
In this post you'll learn to:
Author an XML API catalog with the official DTD.
Bind it to a plain Java interface automatically.
Use #{...} context variables in XML.
Swap endpoint behavior without recompiling business code.
The Big Idea
apis.xml (curl commands + return types) business code
| |
+-- parsed by JQuickCurlXmlParseFactory ----------> plain interface proxy
The XML file names each request and declares its return type. The factory binds those entries to interface methods by method name. Change the curl in XML → the running app changes behavior. No Java edits, no rebuild.
Step 1: Write the XML Catalog
Save this as src/main/resources/apis.xml. The DOCTYPE references the bundled DTD so your IDE can validate structure as you type.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE curls PUBLIC "-//PAOHAIJIAO//DTD API CURL 1.0//EN"
"classpath:paohaijiao/dtd/Jquick-curl.dtd">
<curls namespace="com.example.weather.WeatherApi">
<curl name="current" returnClass="java.lang.String">
curl -X GET 'https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41¤t_weather=true'
</curl>
<curl name="currentAt" returnClass="java.lang.String">
curl -X GET 'https://api.open-meteo.com/v1/forecast?latitude=#{lat}&longitude=#{lon}¤t_weather=true'
</curl>
<curl name="sunrise" returnClass="java.lang.String">
curl -X GET 'https://api.sunrise-sunset.org/json?lat=#{lat}&lng=#{lon}&formatted=0'
</curl>
</curls>
Rules to remember while authoring:
<curls namespace="..."> identifies the interface the file maps to.
Each <curl> has name (must equal the Java method name) and returnClass (fully qualified).
The text content is the curl command; #{name} placeholders are resolved at runtime from context/method parameters.
Optional <if>, <foreach>, and <choose> children make content conditional (Post 8 covers <if> in depth).
Step 2: Write a Pure Java Interface
No annotations, no HTTP imports — just signatures matching the name attributes. Parameters are bound with @Param("...") (import from the xml module) so the XML can reference them via #{...}:
import com.github.paohaijiao.xml.param.Param;
public interface WeatherApi {
String current();
String currentAt(@Param("lat") double lat, @Param("lon") double lon);
String sunrise(@Param("lat") double lat, @Param("lon") double lon);
}
Step 3: Build the Proxy from the XML Factory
JQuickCurl ships its own parse handler; the generic XML-proxy factory comes from the companion library:
import com.github.paohaijiao.xml.JQuickCurlXmlParseFactory;
import com.github.paohaijiao.xml.factory.JQuickXmlFactory;
import com.github.paohaijiao.xml.handler.JQuickParseHandler;
public class XmlDemo {
public static void main(String[] args) {
// 1. Parser that understands JQuickCurl XML.
JQuickParseHandler parser = new JQuickCurlXmlParseFactory();
// 2. Factory bound to the classpath resource "apis.xml".
JQuickXmlFactory factory = new JQuickXmlFactory(parser, "apis.xml");
// 3. One proxy for the whole catalog.
WeatherApi api = factory.createApi(WeatherApi.class);
System.out.println(api.current());
System.out.println(api.currentAt(52.52, 13.41));
System.out.println(api.sunrise(52.52, 13.41));
}
}
Expected output: JSON from Open-Meteo and the sunrise/sunset API. The calls above run without authentication and prove the whole round trip.
A Second Catalog Without Touching Java
Want to point current at a different provider, add a header, or insert retry semantics? Edit only the XML:
<curl name="current" returnClass="java.lang.String">
curl -X GET 'https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41¤t_weather=true' \
-H 'Accept: application/json'
</curl>
The proxy, the interface, and all callers stay unchanged. That is the entire value proposition: API drift is fixed in one configuration file, not across dozens of call sites.
XML Mode vs Annotation Mode — When to Choose Which
Dimension
Annotation mode (@JCurlCommand)
XML mode (apis.xml)
Request location
Next to Java code
Centralized config file
Change without rebuild
No
Yes
IDE help
Java syntax
XML + DTD validation
Variables
${name} from JQuickCurlReq
#{name} from context / @Param args
Best fit
Few endpoints, team owns the code
Large third-party API catalogs, shared config
Summary
XML configuration mode decouples what the HTTP call is from who calls it. You get one searchable, validated, DTD-checked catalog of every integration your service owns, while Java interfaces stay free of annotation noise. This pattern pays off exactly when your API surface is wide and changes often.
Source project: dromara/jquick-curl. Post 8 pushes XML mode further with <if> conditions that render parts of a request only when runtime state says so.
java #springboot #httpclient #opensource #java-library
Read original: https://dev.to/paohaijiao/xml-configuration-mode-decoupling-your-api-catalog-from-business-code-56nm
← Previous
Missing RLS: The Most Underrated Breach Cause of 2026
Next →
Padrão de Projeto Decorator: Adicionando Funcionalidades sem Quebrar sua Arquitetura
Related
Production API Key Rotation Explained: 6 Least-Privilege Checks for Node.js GitHub Actions
Backend
0
Dev.to (EN Zone)
Padrão de Projeto Decorator: Adicionando Funcionalidades sem Quebrar sua Arquitetura
Backend
1
DEV Community
Build a small OpenOSRS plugin in Java
Backend
0
DEV Community
[showoff Saturday] I got hooked on Advent of Code and wanted it all year, so I built a site that gives everyone the same coding challenge every day
Backend
0
Reddit r/webdev
Comments0
No comments yet — be the first