Spring Boot Automatic Protobuf Schema Registration

What You Will Learn

How to use the Infinispan Spring Boot starter with automatic Protobuf schema registration. Starting with Infinispan 16.2, the starter automatically discovers GeneratedSchema implementations on the classpath, registers them as serialization context initializers, and uploads the schemas to the Infinispan Server at startup. No manual schemas().createOrUpdate() call is needed.

This tutorial builds a REST application that stores indexed characters in a remote cache and performs full-text search queries.

Prerequisites

  • Java 17+

  • Spring Boot

  • Docker or Podman (optional)

You can start an Infinispan Server manually with Docker or Podman:

docker run -it --rm -p 11222:11222 -e USER=admin -e PASS=password quay.io/infinispan/server:latest
Tip
You can replace docker with podman in the command above if you use Podman.
Tip
If no server is running on localhost:11222, the application automatically starts an Infinispan container using Testcontainers.

Step 1: Add Dependencies

Add the Infinispan Spring Boot remote starter and the ProtoStream annotation processor:

<dependency>
   <groupId>org.infinispan</groupId>
   <artifactId>infinispan-spring-boot4-starter-remote</artifactId>
</dependency>
<dependency>
   <groupId>org.infinispan.protostream</groupId>
   <artifactId>protostream-processor</artifactId>
</dependency>

Step 2: Configure the Connection and Cache

In application.properties, configure the connection, the marshaller, and the cache definition:

infinispan.remote.connection-uri=hotrod://admin:password@127.0.0.1:11222

# Per-cache configuration: point to the cache XML definition and ProtoStreamMarshaller marshaller
infinispan.remote.cache.characters.configuration-uri=classpath:indexedCache.xml
infinispan.remote.cache.characters.marshaller=org.infinispan.commons.marshall.ProtoStreamMarshaller

characters.filename=characters.csv

# Protobuf schemas are automatically discovered and uploaded to the server at startup.
# To disable this behavior, uncomment the following property:
# infinispan.remote.use-schema-registration=false

Key points:

  • infinispan.remote.connection-uri provides the connection string including credentials.

  • infinispan.remote.cache.characters.configuration-uri points to a classpath XML file that defines the cache.

  • infinispan.remote.cache.characters.marshaller is set to ProtoStreamMarshaller because the default is JavaSerializationMarshaller.

  • There is no manual schema registration code. The starter automatically discovers and uploads Protobuf schemas at startup.

  • To disable auto schema upload, set infinispan.remote.use-schema-registration=false.

Step 3: Define a Protobuf Entity

Create an indexed Protobuf record with @Text fields for full-text search:

@Proto
@Indexed
public record Character(UUID id, @Text String name, @Text String bio, Archetype archetype) {

}

Step 4: Define the Protobuf Schema

Create a @ProtoSchema interface that extends GeneratedSchema. The starter will discover this interface automatically on the classpath, register it with the serialization context, and upload the generated .proto schema to the server:

@ProtoSchema(schemaPackageName = "tutorial",
      includeClasses = {Character.class, Archetype.class},
      dependsOn = {
            org.infinispan.protostream.types.java.CommonTypes.class
      })
public interface AppSchema extends GeneratedSchema {
}

Step 5: Query the Cache

Inject the RemoteCacheManager and perform full-text queries using Ickle:

@Service
public class CharacterSearch {

   private final RemoteCache<String, Character> characters;

   public CharacterSearch(RemoteCacheManager remoteCacheManager) {
      this.characters = remoteCacheManager.getCache("characters");
   }

   public Character getById(String id) {
      return characters.get(id);
   }

   public Set<String> search(String term) {
      String query = "FROM tutorial.Character c"
            + " WHERE c.name:'~" + term + "'"
            + " OR c.bio: '~" + term + "'";

      List<Character> result = characters.<Character>query(query).execute().list();
      return result.stream().map(Character::name).collect(Collectors.toSet());
   }
}

Step 6: Expose REST Endpoints

Create a Spring @RestController that exposes the search service:

@RestController
@RequestMapping("/characters")
public class CharactersResource {

   private final CharacterSearch searchService;

   public CharactersResource(CharacterSearch searchService) {
      this.searchService = searchService;
   }

   @GetMapping("/{id}")
   public Character byId(@PathVariable("id") String id) {
      Character character = searchService.getById(id);
      if (character == null) {
         throw new ResponseStatusException(HttpStatus.NOT_FOUND,
               "Character with id of " + id + " does not exist.");
      }
      return character;
   }

   @GetMapping("/query")
   public Set<String> searchCharacter(@RequestParam(value = "term", required = false) String term) {
      if (term == null) {
         return Collections.emptySet();
      }
      return searchService.search(term);
   }
}

Step 7: Run the Tutorial

mvn spring-boot:run

Then query the REST endpoints:

curl http://localhost:8080/characters/0
curl "http://localhost:8080/characters/query?term=Felix"

How Auto Schema Registration Works

The Infinispan Spring Boot starter (16.2+) automatically:

  1. Scans your application packages for GeneratedSchema implementations using Spring’s classpath scanning.

  2. Registers them as SerializationContextInitializer instances with the RemoteCacheManager.

  3. Uploads the .proto schemas to the Infinispan Server via RemoteSchemasAdmin.createOrUpdate().

This is controlled by the infinispan.remote.use-schema-registration property, which defaults to true.

Note
The auto-discovery scans packages registered with Spring Boot’s AutoConfigurationPackages and skips internal Infinispan packages (org.infinispan.*). Make sure your application uses a different base package so the scanner picks up your schema.

What’s Next