or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

codecs.mdhttp-clients.mdhystrix.mdindex.mdjaxrs.mdjson-processing.mdxml-processing.md
tile.json

xml-processing.mddocs/

XML Processing

Feign provides comprehensive XML support through JAXB and SAX for XML request and response handling.

Capabilities

JAXB Support

JAXB-based XML encoding and decoding for object-to-XML marshalling.

/**
 * XML encoder using JAXB for marshalling objects to XML
 */
public class JAXBEncoder implements Encoder {
  /** Create encoder with default JAXB context factory */
  public JAXBEncoder();
  
  /** Create encoder with custom JAXB context factory */
  public JAXBEncoder(JAXBContextFactory jaxbContextFactory);
  
  /** Encode object to XML request body */
  public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException;
}

/**
 * XML decoder using JAXB for unmarshalling XML to objects
 */
public class JAXBDecoder implements Decoder {
  /** Create decoder with default JAXB context factory */
  public JAXBDecoder();
  
  /** Create decoder with custom JAXB context factory */
  public JAXBDecoder(JAXBContextFactory jaxbContextFactory);
  
  /** Decode XML response to object */
  public Object decode(Response response, Type type) throws IOException, DecodeException;
}

/**
 * Factory for creating and caching JAXB contexts
 */
public interface JAXBContextFactory {
  /** Create or retrieve cached JAXB context for classes */
  JAXBContext createContext(Class<?>... classes) throws JAXBException;
  
  /** Default implementation with context caching */
  public static class Default implements JAXBContextFactory;
}

SAX Support

SAX-based XML parsing for streaming XML processing.

/**
 * XML decoder using SAX parser for efficient XML processing
 */
public class SAXDecoder implements Decoder {
  /** Create decoder builder for configuration */
  public static Builder builder();
  
  /** Decode XML response using registered content handlers */
  public Object decode(Response response, Type type) throws IOException, DecodeException;
  
  /**
   * Builder for configuring SAX decoder
   */
  public static class Builder {
    /** Register content handler for specific type */
    public Builder registerContentHandler(Class<?> type, ContentHandlerFactory contentHandlerFactory);
    
    /** Register content handler class */
    public Builder registerContentHandler(Class<? extends DefaultHandler> handlerClass);
    
    /** Build configured SAX decoder */
    public SAXDecoder build();
  }
}

Usage Examples

Basic JAXB Usage

import feign.Feign;
import feign.jaxb.JAXBEncoder;
import feign.jaxb.JAXBDecoder;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlElement;

@XmlRootElement(name = "user")
class User {
    @XmlElement(name = "id")
    private String id;
    
    @XmlElement(name = "name")
    private String name;
    
    @XmlElement(name = "email")
    private String email;
    
    // constructors, getters, setters
}

// Basic JAXB configuration
UserAPI userAPI = Feign.builder()
    .encoder(new JAXBEncoder())
    .decoder(new JAXBDecoder())
    .target(UserAPI.class, "https://api.example.com");

// API calls automatically marshal/unmarshal XML
User user = userAPI.getUser("123");
userAPI.createUser(new User("456", "John Doe", "john@example.com"));

Custom JAXB Context Factory

import feign.jaxb.JAXBContextFactory;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;

class CustomJAXBContextFactory implements JAXBContextFactory {
    @Override
    public JAXBContext createContext(Class<?>... classes) throws JAXBException {
        // Custom context creation with specific configuration
        return JAXBContext.newInstance(classes);
    }
}

UserAPI userAPI = Feign.builder()
    .encoder(new JAXBEncoder(new CustomJAXBContextFactory()))
    .decoder(new JAXBDecoder(new CustomJAXBContextFactory()))
    .target(UserAPI.class, "https://api.example.com");

SAX Decoder Usage

import feign.Feign;
import feign.sax.SAXDecoder;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.Attributes;

// Custom SAX content handler
class UserHandler extends DefaultHandler {
    private User user;
    private StringBuilder currentValue = new StringBuilder();
    
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) {
        if ("user".equals(qName)) {
            user = new User();
        }
        currentValue.setLength(0);
    }
    
    @Override
    public void characters(char[] ch, int start, int length) {
        currentValue.append(ch, start, length);
    }
    
    @Override
    public void endElement(String uri, String localName, String qName) {
        if ("id".equals(qName)) {
            user.setId(currentValue.toString());
        } else if ("name".equals(qName)) {
            user.setName(currentValue.toString());
        } else if ("email".equals(qName)) {
            user.setEmail(currentValue.toString());
        }
    }
    
    public User getUser() {
        return user;
    }
}

// Configure SAX decoder
UserAPI userAPI = Feign.builder()
    .decoder(SAXDecoder.builder()
        .registerContentHandler(UserHandler.class)
        .build())
    .target(UserAPI.class, "https://api.example.com");

Complex XML Structures

import javax.xml.bind.annotation.*;
import java.util.List;

@XmlRootElement(name = "users")
@XmlAccessorType(XmlAccessType.FIELD)
class UserList {
    @XmlElement(name = "user")
    private List<User> users;
    
    // constructors, getters, setters
}

@XmlRootElement(name = "user")
@XmlAccessorType(XmlAccessType.FIELD)
class User {
    @XmlAttribute
    private String id;
    
    @XmlElement
    private String name;
    
    @XmlElement
    private String email;
    
    @XmlElement(name = "address")
    private Address address;
    
    @XmlElementWrapper(name = "tags")
    @XmlElement(name = "tag")
    private List<String> tags;
}

@XmlAccessorType(XmlAccessType.FIELD)
class Address {
    private String street;
    private String city;
    private String country;
}

interface UserAPI {
    @RequestLine("GET /users")
    @Headers("Accept: application/xml")
    UserList getAllUsers();
    
    @RequestLine("GET /users/{id}")
    @Headers("Accept: application/xml")
    User getUser(@Param("id") String id);
    
    @RequestLine("POST /users")
    @Headers({"Content-Type: application/xml", "Accept: application/xml"})
    User createUser(User user);
}

Namespace Handling

@XmlRootElement(name = "user", namespace = "http://example.com/user")
@XmlAccessorType(XmlAccessType.FIELD)
class User {
    @XmlElement(namespace = "http://example.com/user")
    private String id;
    
    @XmlElement(namespace = "http://example.com/user")
    private String name;
}

// JAXB automatically handles namespaces
UserAPI userAPI = Feign.builder()
    .encoder(new JAXBEncoder())
    .decoder(new JAXBDecoder())
    .target(UserAPI.class, "https://api.example.com");

Installation

JAXB Module

dependencies {
    compile 'com.netflix.feign:feign-jaxb:8.18.0'
}

SAX Module

dependencies {
    compile 'com.netflix.feign:feign-sax:8.18.0'
}

Configuration Tips

JAXB Configuration

// Custom marshaller properties
JAXBContextFactory factory = new JAXBContextFactory() {
    @Override
    public JAXBContext createContext(Class<?>... classes) throws JAXBException {
        JAXBContext context = JAXBContext.newInstance(classes);
        return context;
    }
};

// Configure marshaller/unmarshaller
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");

Error Handling

// Custom error decoder for XML APIs
ErrorDecoder xmlErrorDecoder = new ErrorDecoder() {
    @Override
    public Exception decode(String methodKey, Response response) {
        if (response.status() >= 400) {
            try {
                // Parse XML error response
                ErrorResponse error = (ErrorResponse) new JAXBDecoder()
                    .decode(response, ErrorResponse.class);
                return new CustomAPIException(error.getMessage(), error.getCode());
            } catch (Exception e) {
                return new FeignException(response.status(), "XML parsing failed");
            }
        }
        return null;
    }
};

UserAPI userAPI = Feign.builder()
    .encoder(new JAXBEncoder())
    .decoder(new JAXBDecoder())
    .errorDecoder(xmlErrorDecoder)
    .target(UserAPI.class, "https://api.example.com");

Performance Considerations

JAXB Performance

  • Context creation is expensive - use caching (default factory provides this)
  • Consider using SAX for large XML documents
  • Pool marshaller/unmarshaller instances for high-throughput scenarios

SAX Performance

  • More memory efficient for large XML documents
  • Streaming processing reduces memory footprint
  • Requires custom content handlers for each data type