Serializing and Deserializing Messages with the Solace JMS API
You can use the Solace JMS API with the SERDES Collection to handle structured message payloads efficiently. SERDES, which stands for Serialization and Deserialization, allows applications to convert complex data structures into a compact, transmittable format when publishing messages and to reconstruct them when consuming messages. This is particularly useful when integrating with schema registries. The SERDES Collection refers to the set of serializer and deserializer libraries, such as Solace Avro SERDES for Java, Solace JSON Schema SERDES for Java, and Generic SERDES for Java. You can use these libraries to integrate applications with Solace Schema Registry for schema-based message serialization and deserialization.
- Prerequisites
- Deploying with Maven
- JMS Message Type Support
- Serializing and Deserializing Messages with Avro
- Serializing and Deserializing Messages with JSON Schema
Prerequisites
Before implementing SERDES with the Solace JMS API, you should understand the language-agnostic concepts and configuration options covered in Serialization and Deserialization with Solace Schema Registry. Key topics include:
- Connecting to Schema Registry (authentication and security)
- Choosing schema resolution strategies (Destination ID, Topic ID, Topic ID with Profiles, Record ID)
- Optimizing performance (caching and lookup options)
- Advanced configuration (auto-registration, header formats, Avro and JSON Schema-specific settings)
- Cross-protocol message translation
The following sections focus on Solace JMS API-specific implementation details, including Java imports and code examples for serializing and deserializing messages.
Deploying with Maven
To use the SERDES Collection with the Solace JMS API, you need to include the appropriate Maven dependencies in your project. The SERDES libraries are distributed as separate artifacts that you can include based on your serialization format requirements.
The following sections show you how to configure your Maven project to include the necessary dependencies for schema registry integration:
- SERDES BOM Dependencies
- Avro Serializer Dependencies
- JSON Schema Serializer Dependencies
- Generic Serializer Dependencies
SERDES BOM Dependencies
The SERDES Bill of Materials (BOM) provides a centralized way to manage compatible versions of all Solace Schema Registry SERDES components. Using the BOM is the recommended approach because it ensures that all SERDES dependencies are aligned with tested and compatible versions, which simplifies dependency management and reduces version conflicts in your applications.
The BOM includes version management for:
- Avro SERDES components
- JSON Schema SERDES components
- Common SERDES libraries
- Compatible versions of underlying dependencies
To use the SERDES BOM, add it to your Maven pom.xml file in the dependencyManagement section:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.solace</groupId>
<artifactId>solace-schema-registry-serdes-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
After importing the BOM, you can add SERDES dependencies without specifying versions:
<dependencies>
<!-- JMS API -->
<dependency>
<groupId>com.solacesystems</groupId>
<artifactId>sol-jms</artifactId>
<version>10.30.0</version>
</dependency>
<!-- Avro SERDES (version managed by BOM) -->
<dependency>
<groupId>com.solace</groupId>
<artifactId>solace-schema-registry-avro-serde</artifactId>
</dependency>
<!-- JSON Schema SERDES (version managed by BOM) -->
<dependency>
<groupId>com.solace</groupId>
<artifactId>solace-schema-registry-jsonschema-serde</artifactId>
</dependency>
</dependencies>
Avro Serializer Dependencies
The Avro serializer provides a specific implementation for Apache Avro serialization and deserialization. This dependency includes the AvroSerializer, AvroDeserializer, and Avro-specific configuration properties, and also brings in the required common SERDES components used across all schema formats.
Add the following dependency to your Maven pom.xml file:
<dependencies>
<dependency>
<groupId>com.solace</groupId>
<artifactId>solace-schema-registry-avro-serde</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
For the latest version information and additional details about the Avro SERDES artifact, see the Maven Central Repository.
Important considerations when adding Maven dependencies:
- Always use the latest compatible versions of both the Solace JMS API and SERDES libraries for optimal performance and security.
- The Avro SERDES dependency automatically includes the necessary Apache Avro libraries as transitive dependencies.
JSON Schema Serializer Dependencies
The JSON Schema serializer provides a specific implementation for JSON Schema serialization and deserialization. This dependency includes the JsonSchemaSerializer, JsonSchemaDeserializer, and JSON Schema-specific configuration properties, and also brings in the required common SERDES components used across all schema formats.
Add the following dependency to your Maven pom.xml file:
<dependencies>
<dependency>
<groupId>com.solace</groupId>
<artifactId>solace-schema-registry-jsonschema-serde</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
For the latest version information and additional details about the JSON Schema SERDES artifact, see the Maven Central Repository.
Important considerations when adding Maven dependencies:
- Always use the latest compatible versions of both the Solace JMS API and SERDES libraries for optimal performance and security.
- The JSON Schema SERDES dependency automatically includes the necessary JSON Schema validation libraries as transitive dependencies.
Generic Serializer Dependencies
The Generic SERDES for Java provides simple string serialization and deserialization capabilities with no Solace Schema Registry interaction. Generic SERDES for Java is not typically used with the Solace JMS API, as JMS provides its own message type conversions. For schema-based serialization, use the Avro or JSON Schema SERDES instead.
JMS Message Type Support
The Solace JMS API supports the following message types when using SERDES:
- BytesMessage — Recommended for both publishing and consuming SERDES messages. This message type provides the most efficient and reliable transport for serialized data. All examples on this page use
BytesMessage. - TextMessage — Supported for receiving messages. When consuming messages that may have been published via other protocols (such as REST), your application should be prepared to handle both
BytesMessageandTextMessageobjects. The deserializer can process the payload from either message type. While technically possible to send SERDES messages usingTextMessage,BytesMessageis strongly recommended for publishing.
The SERDES serializer returns binary data as a byte array, which you write to a BytesMessage. The serializer also populates a headers map with schema metadata, which you must set as message properties on the JMS message. This approach ensures schema information is preserved during message transmission and enables interoperability with other Solace messaging protocols.
Important considerations for JMS message types with SERDES:
- When publishing messages, always use
BytesMessagefor optimal performance and cross-protocol compatibility. - When consuming messages, handle both
BytesMessageandTextMessageto support messages published via REST or other protocols. - Do not use
ObjectMessagewith SERDES.ObjectMessagehas its own Java serialization mechanism that is incompatible with schema registry integration.
Serializing and Deserializing Messages with Avro
The example below shows you how to create a configuration map, an AvroSerializer object, and an AvroDeserializer object:
// 1. Set SERDES properties using a configuration HashMap Map<String, Object> config = new HashMap<>(); // Configure schema registry connection (required) config.put(SchemaResolverProperties.REGISTRY_URL, "http://localhost:8081/apis/registry/v3"); config.put(SchemaResolverProperties.AUTH_USERNAME, "myUsername"); config.put(SchemaResolverProperties.AUTH_PASSWORD, "myPassword"); // Configure Avro-specific properties (optional) config.put(AvroProperties.ENCODING_TYPE, AvroProperties.AvroEncoding.BINARY); // 2. Create and configure your serializer object Serializer<GenericRecord> serializer = new AvroSerializer<>(); serializer.configure(config); // 3. Create and configure your deserializer object Deserializer<GenericRecord> deserializer = new AvroDeserializer<>(); deserializer.configure(config);
For detailed information about all available configuration properties, see Getting Started with SERDES and Avro-Specific Configuration.
The following sections explain how to serialize and deserialize messages with the Solace JMS API:
- Serializing and Sending Avro Messages Using the Solace JMS API
- Receiving and Deserializing Avro Messages Using the Solace JMS API
Serializing and Sending Avro Messages Using the Solace JMS API
When serializing Avro messages with the Solace JMS API, you call the serializer to convert your Avro-generated Java object to binary format, then manually set the schema headers as JMS message properties. The example below shows this process:
// 1. Create a User specific record
User user = new User();
user.setId("123");
user.setName("John Doe");
user.setEmail("support@solace.com");
// 2. Serialize the user record using the Avro serializer
Map<String, Object> headers = new HashMap<>();
byte[] payloadBytes = serializer.serialize(TOPIC_NAME, user, headers);
// 3. Create a BytesMessage with the serialized payload
BytesMessage bytesMessage = session.createBytesMessage();
bytesMessage.writeBytes(payloadBytes);
// 4. Set schema registry headers as message properties
for (Map.Entry<String, Object> entry : headers.entrySet()) {
bytesMessage.setObjectProperty(entry.getKey(), entry.getValue());
}
// 5. Send the message
producer.send(bytesMessage);
The serializer.serialize() method converts the data to binary format and populates the headers map with schema information, including the schema identifier and other metadata needed for proper deserialization. You must manually set these headers as JMS message properties using setObjectProperty(). The schema information is transmitted as JMS message properties, not in the payload itself, which enables interoperability with other messaging protocols.
For a complete example, see AvroSerializeProducerSpecificRecord.java on the Solace Samples Repository.
For a complete list of Avro SERDES properties and methods, see the Java Avro SERDES API Reference.
Receiving and Deserializing Avro Messages Using the Solace JMS API
When deserializing Avro messages with the Solace JMS API, you manually extract the payload bytes and schema headers from the JMS message, then pass them to the deserializer. Your application should handle both BytesMessage and TextMessage to support cross-protocol messaging scenarios. The example below shows this process:
// 1. Create a message consumer and subscribe to the topic
MessageConsumer messageConsumer = session.createConsumer(topic);
// 2. Start receiving messages
connection.start();
// 3. Receive a message (blocking call)
Message message = messageConsumer.receive();
if (message != null) {
// 4. Extract payload bytes based on message type
byte[] payloadBytes;
if (message instanceof BytesMessage) {
BytesMessage bytesMessage = (BytesMessage) message;
payloadBytes = new byte[(int) bytesMessage.getBodyLength()];
bytesMessage.readBytes(payloadBytes);
} else if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
payloadBytes = textMessage.getText().getBytes(StandardCharsets.UTF_8);
} else {
System.out.println("Unexpected message type: " + message.getClass().getName());
return;
}
// 5. Extract headers from message properties
Map<String, Object> headers = new HashMap<>();
Enumeration<?> propertyNames = message.getPropertyNames();
while (propertyNames.hasMoreElements()) {
String propertyName = (String) propertyNames.nextElement();
headers.put(propertyName, message.getObjectProperty(propertyName));
}
// 6. Deserialize the message
GenericRecord genericRecord = deserializer.deserialize(TOPIC_NAME, payloadBytes, headers);
System.out.printf("Received message: %s%n", genericRecord);
}
The deserialization process requires three components: the topic name, the message payload as a byte array, and the headers map containing schema metadata. The headers are extracted from JMS message properties using getPropertyNames() and getObjectProperty(). The deserializer uses this information to retrieve the correct schema from the schema registry and reconstruct the original object.
For a complete example, see AvroDeserializeConsumer.java on the Solace Samples Repository.
For a complete list of Avro SERDES properties and methods, see the Java Avro SERDES API Reference.
Serializing and Deserializing Messages with JSON Schema
The example below shows you how to create a configuration map, a JsonSchemaSerializer object, and a JsonSchemaDeserializer object:
// 1. Set SERDES properties using a configuration HashMap Map<String, Object> config = new HashMap<>(); // Configure schema registry connection (required) config.put(SchemaResolverProperties.REGISTRY_URL, "http://localhost:8081/apis/registry/v3"); config.put(SchemaResolverProperties.AUTH_USERNAME, "myUsername"); config.put(SchemaResolverProperties.AUTH_PASSWORD, "myPassword"); // Configure JSON Schema-specific properties (optional) config.put(JsonSchemaProperties.VALIDATE_SCHEMA, true); // 2. Create and configure your serializer object Serializer<User> serializer = new JsonSchemaSerializer<>(); serializer.configure(config); // 3. Create and configure your deserializer object Deserializer<User> deserializer = new JsonSchemaDeserializer<>(); deserializer.configure(config);
For detailed information about all available configuration properties, see Getting Started with SERDES and JSON Schema-Specific Configuration.
The following sections explain how to serialize and deserialize messages with the Solace JMS API:
- Serializing and Sending JSON Schema Messages Using the Solace JMS API
- Receiving and Deserializing JSON Schema Messages Using the Solace JMS API
Serializing and Sending JSON Schema Messages Using the Solace JMS API
When serializing JSON Schema messages with the Solace JMS API, you call the serializer to convert your Java object to binary format, then manually set the schema headers as JMS message properties. The example below shows this process:
// 1. Create and populate a User object with sample data
User user = new User();
user.setName("John Doe");
user.setId("123");
user.setEmail("support@solace.com");
// 2. Serialize the user object using the JSON Schema serializer
Map<String, Object> headers = new HashMap<>();
byte[] payloadBytes = serializer.serialize(TOPIC_NAME, user, headers);
// 3. Create a BytesMessage with the serialized payload
BytesMessage bytesMessage = session.createBytesMessage();
bytesMessage.writeBytes(payloadBytes);
// 4. Set schema registry headers as message properties
for (Map.Entry<String, Object> entry : headers.entrySet()) {
bytesMessage.setObjectProperty(entry.getKey(), entry.getValue());
}
// 5. Send the message
producer.send(bytesMessage);
The serializer.serialize() method converts the data to binary format and populates the headers map with schema information, including the schema identifier and other metadata needed for proper deserialization. You must manually set these headers as JMS message properties using setObjectProperty(). The schema information is transmitted as JMS message properties, not in the payload itself, which enables interoperability with other messaging protocols.
For a complete example, see JsonSchemaSerializeProducer.java on the Solace Samples Repository.
Receiving and Deserializing JSON Schema Messages Using the Solace JMS API
When deserializing JSON Schema messages with the Solace JMS API, you manually extract the payload bytes and schema headers from the JMS message, then pass them to the deserializer. Your application should handle both BytesMessage and TextMessage to support cross-protocol messaging scenarios. The example below shows this process:
// 1. Create a message consumer and subscribe to the topic
MessageConsumer messageConsumer = session.createConsumer(topic);
// 2. Start receiving messages
connection.start();
// 3. Receive a message (blocking call)
Message message = messageConsumer.receive();
if (message != null) {
// 4. Extract payload bytes based on message type
byte[] payloadBytes;
if (message instanceof BytesMessage) {
BytesMessage bytesMessage = (BytesMessage) message;
payloadBytes = new byte[(int) bytesMessage.getBodyLength()];
bytesMessage.readBytes(payloadBytes);
} else if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
payloadBytes = textMessage.getText().getBytes(StandardCharsets.UTF_8);
} else {
System.out.println("Unexpected message type: " + message.getClass().getName());
return;
}
// 5. Extract headers from message properties
Map<String, Object> headers = new HashMap<>();
Enumeration<?> propertyNames = message.getPropertyNames();
while (propertyNames.hasMoreElements()) {
String propertyName = (String) propertyNames.nextElement();
headers.put(propertyName, message.getObjectProperty(propertyName));
}
// 6. Deserialize the message
User user = deserializer.deserialize(TOPIC_NAME, payloadBytes, headers);
System.out.println("Received JSON schema message: " + user);
}
The deserialization process requires three components: the topic name, the message payload as a byte array, and the headers map containing schema metadata. The headers are extracted from JMS message properties using getPropertyNames() and getObjectProperty(). The deserializer uses this information to retrieve the correct schema from the schema registry and reconstruct the original object.
For a complete example, see JsonSchemaDeserializeConsumerToPojo.java on the Solace Samples Repository.
For a complete list of JSON Schema SERDES properties and methods, see the Java JSON SERDES API Reference.