HttpMessageConverters class final

A composite registry and container for managing HttpMessageConverter pods.

Overview

The HttpMessageConverters serves as the central hub for HTTP message converter management in the Jetleaf framework. It implements multiple roles:

  • Registry Interface: Allows programmatic converter registration via add
  • Container: Maintains an ordered collection of all available converters
  • Discovery Engine: Automatically discovers converters and registrars from the application context
  • Ordering Service: Applies proper ordering to converters for content negotiation

Key Responsibilities

  • Automatic Discovery: Finds all HttpMessageConverter and HttpMessageConverterRegistrar pods
  • Deduplication: Ensures each converter is registered only once
  • Order Management: Applies AnnotationAwareOrderComparator for proper converter priority
  • Lifecycle Integration: Implements SmartInitializingSingleton for startup initialization
  • Framework Integration: Implements ApplicationContextAware for dependency access

Framework Integration Flow

During application startup:

  1. Context Awareness: Framework injects ApplicationContext via setApplicationContext
  2. Pod Initialization: Framework calls onReady when context is ready
  3. Registrar Discovery: Finds and invokes all HttpMessageConverterRegistrar pods
  4. Converter Discovery: Finds and registers all HttpMessageConverter pods
  5. Ordering Application: Sorts converters using AnnotationAwareOrderComparator
  6. Ready State: Converter collection becomes available via getMessageConverters

Example: Manual Registration

@Pod
class CustomConverterSetup {
  final HttpMessageConverters _compositeConverter;

  CustomConverterSetup(this._compositeConverter);

  @PostConstruct
  void setupConverters() {
    // Manually register custom converters
    _compositeConverter.add(CustomJsonConverter());
    _compositeConverter.add(ProtobufConverter());
  }
}

Example: Registrar-Based Registration

@Pod
class CustomConverterRegistrar implements HttpMessageConverterRegistrar {
  @override
  void register(HttpMessageConverterRegistry registry) {
    registry.add(CustomJsonConverter());
    registry.add(ProtobufConverter());
  }
}

// The HttpMessageConverters will automatically discover
// and invoke this registrar during onReady()

Converter Ordering Strategy

Converters are ordered using AnnotationAwareOrderComparator which considers:

  • @Order annotations on converter classes
  • @Priority annotations on converter classes
  • Natural ordering based on converter capabilities
  • Registration order as fallback

Typical Converter Order

The framework typically orders converters by specificity:

  1. ByteArrayHttpMessageConverter - Most specific (binary data)
  2. StringHttpMessageConverter - Text content
  3. FormHttpMessageConverter - Form data
  4. JsonHttpMessageConverter - JSON data
  5. XmlHttpMessageConverter - XML data
  6. Generic Converters - Least specific/catch-all

Content Negotiation Process

When processing HTTP messages, the framework:

  1. Retrieves Converters: Gets ordered list via getMessageConverters()
  2. Iterates in Order: Processes converters from most to least specific
  3. First Match Wins: Uses the first converter that can handle the media type
  4. Fallback Handling: May use default converters if no specific match found

Thread Safety

The implementation uses synchronization for concurrent access:

  • Converter registration is thread-safe via synchronized
  • Converter retrieval provides an unmodifiable view
  • Once initialized, the converter list is effectively immutable

Error Handling

  • Duplicate Converters: Silently deduplicated during registration
  • Self-Registration: HttpMessageConverters ignores itself during discovery
  • Missing Context: Fails gracefully if application context not set
  • Empty Registry: Handles scenarios with no converters gracefully

Best Practices

  • Use registrars for modular converter configuration
  • Apply @Order annotations for explicit priority control
  • Register specific converters before generic ones
  • Consider performance implications of large converter collections
  • Test content negotiation with your specific converter mix

Integration Example

@Pod
class HttpMessageProcessor {
  final HttpMessageConverters _converter;

  HttpMessageProcessor(this._converter);

  Future<void> processRequest(HttpInputMessage request, HttpOutputMessage response) async {
    final converters = _converter.getMessageConverters();
    
    // Use converters for content negotiation and processing
    for (final converter in converters) {
      if (converter.canRead(User.class, request.headers.contentType)) {
        final user = await converter.read(User.class, request);
        // Process user...
        break;
      }
    }
  }
}

Summary

The HttpMessageConverters provides a robust, auto-discovering, ordered container for HTTP message converters, serving as the cornerstone of Jetleaf's content negotiation and message processing capabilities.

Implemented types

Constructors

HttpMessageConverters()
A composite registry and container for managing HttpMessageConverter pods.

Properties

hashCode int
The hash code for this object.
no setterinherited
runtimeType Type
A representation of the runtime type of the object.
no setterinherited

Methods

add(HttpMessageConverter converter) → void
Registers a HttpMessageConverter instance with this registry.
override
findReadable(Class type, MediaType? mediaType) HttpMessageConverter?
Finds the first HttpMessageConverter capable of reading the given type.
findWritable(Class type, MediaType mediaType) HttpMessageConverter?
Finds the first HttpMessageConverter capable of writing the given type.
getMessageConverters() List<HttpMessageConverter>
Returns an ordered, unmodifiable list of all registered message converters.
getPackageName() String
Represents an abstraction for identifying the package that an object, resource, or service belongs to.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
onReady() Future<void>
Interface to be implemented by pods that require initialization logic after their properties have been set by the container.
setApplicationContext(ApplicationContext applicationContext) → void
Sets the ApplicationContext that this component runs in.
toString() String
A string representation of this object.
inherited

Operators

operator ==(Object other) bool
The equality operator.
inherited