---
name: java-xmlrpc-guideline
description: Use when Java XML-RPC API work requires contract decisions for fault signaling and interoperability, including defining XmlRpcException-based failures, replacing void returns with explicit operation results, reviewing handlers for return-code anti-patterns, and migrating DTOs from Serializable to JAXB.
---
# Java XML-RPC API Design Guideline
## Overview
Design XML-RPC APIs with clear exception handling, proper return types, and interoperable serialization.
**Core principle:** Exceptions signal failure, return values signal success. Use JAXB for cross-language compatibility.
## Quick Reference
| Scenario | Pattern |
|----------|---------|
| API interface method | `ReturnType method(Param p) throws XmlRpcException` |
| Void-like operation | Return `int`, always `0` (value is meaningless, workaround for spec limitation) |
| Success result | Return value (DTO, primitive, etc.) |
| Failure result | Throw `XmlRpcException` |
| DTO serialization | Use JAXB annotations (`@XmlRootElement`, `@XmlAttribute`) |
## Exception Handling
### All API Methods Must Declare XmlRpcException
Every interface method must include `throws XmlRpcException`:
```java
public interface SomeApi {
SomeDto someAction(SomeParameterDto request) throws XmlRpcException;
}
```
**Why:** XML-RPC library can transmit one exception type to client. Most projects use extension features enabling this. The exception serializes as:
```xml
faultCode
1
faultString
failed to execute api
```
**Avoid:** `enabledForException` feature. It serializes Java exceptions including chained exceptions, but only works with Java clients.
## Return Type Guidelines
### Void Methods Must Return int
XML-RPC library doesn't support `void` return type. Use `int` instead:
```java
public interface ServiceControlApi {
int start(String name) throws XmlRpcException;
}
```
**Rules:**
- Always return `0` (regardless of success or failure)
- Signal failure by throwing `XmlRpcException`
- The return value has no meaning - it exists only because XML-RPC spec doesn't support `void`
**Why:** This is purely a workaround for XML-RPC library limitation. If the spec supported `void`, we would use `void`. The `int` return is meaningless; failure is communicated exclusively through exceptions.
### Success vs Failure: Clear Separation
| Outcome | How to Signal |
|---------|---------------|
| Operation succeeded | Return value |
| Query found nothing | Return empty/false (this is success) |
| Operation failed | Throw `XmlRpcException` |
**Example - Query API:**
```java
public interface PublicIpApi {
boolean isExists(InetAddress address) throws XmlRpcException;
}
```
- IP exists → return `true`
- IP doesn't exist → return `false` (success case - query worked)
- System error during query → throw `XmlRpcException`
**Example - Action API:**
```java
public interface ServiceControlApi {
int start(String name) throws XmlRpcException;
}
```
- Service started → return `0`
- Service already running → return `0` (value is meaningless)
- Service failed to start → throw `XmlRpcException` (this is how failure is signaled)
**Why this matters:**
- Returning error codes in response (like `-1` or error field in DTO) makes XML-RPC request appear successful
- Server logs show success, no stack trace
- Client must inspect response to detect failure
- Debugging becomes difficult
## DTO Serialization
### Use JAXB, Not Serializable
DTOs must use XML structures via JAXB for cross-language compatibility:
```java
// GOOD: JAXB DTO
@XmlRootElement
public class ComplexJaxbDto implements Element {
@XmlAttribute
private String type;
@XmlAttribute
private String number;
private List nestedDtos;
private ComplexJaxbDto() { }
public static final class NestedDto {
private String value;
private NestedDto() { }
}
}
```
```java
// BAD: Serializable DTO (Java-only)
public class SerializableDto implements Serializable {
private String value;
public SerializableDto(String value) {
this.value = value;
}
}
```
### Serialization Comparison
**Serializable output (unreadable, Java-only):**
```xml
rO0ABXNyACx0aWwueG1scnBj...
```
**JAXB output (readable, cross-language):**
```xml
test
test2
```
**Why JAXB:**
- XML-RPC is designed for interoperability
- Serializable limits clients to Java
- JAXB produces human-readable XML
- Long-term maintainability
## Common Mistakes
| Mistake | Problem | Fix |
|---------|---------|-----|
| Missing `throws XmlRpcException` | Client can't receive errors | Add to all API methods |
| Using `void` return type | XML-RPC library doesn't support it | Use `int`, always return `0` |
| Returning `-1` or other codes | Meaningless, creates confusion | Always return `0`, use exception for failure |
| Error codes in DTO fields | Request appears successful | Throw `XmlRpcException` |
| Using `Serializable` | Java-only, unreadable | Use JAXB annotations |
| Using `enabledForException` | Java-only | Avoid, use standard faults |
## Idempotency Decisions
For action APIs, decide if operation should be idempotent:
**Idempotent approach:**
- `start()` on running service → return `0`
- Easier for clients, more forgiving
**Strict approach:**
- `start()` on running service → throw `XmlRpcException`
- Explicit about state transitions
Document your choice in the API contract. Either is valid - consistency matters.
## Checklist
Before completing XML-RPC API design:
- [ ] All interface methods declare `throws XmlRpcException`
- [ ] No `void` return types (use `int`, always return `0`)
- [ ] Success cases return values (for non-void methods)
- [ ] Failure cases throw exceptions (never use return codes)
- [ ] For void-like methods: return value is always `0`, failure via exception only
- [ ] Idempotency behavior documented