xAPI Java is a library that helps you create applications that send or receive xAPI Statements or Documents. This is a Maven-based monorepo containing multiple projects:
- xapi-model: Core data models for xAPI statements, actors, verbs, activities, and related objects
- xapi-client: Client library for communicating with Learning Record Stores (LRS)
- xapi-model-spring-boot-starter: Spring Boot autoconfiguration for xAPI model validation
- samples: Example applications demonstrating xAPI client usage and a simple Learning Record Store (LRS).
- Language: Java 25 or newer (required)
- Build Tool: Maven (using Maven Wrapper
./mvnw) - Framework: Spring Boot 3.5.7, Spring WebClient (reactive)
- Code Style: Google Java Style Guide enforced via CheckStyle
- Testing: JUnit 5 (Jupiter), Hamcrest matchers
- Code Generation: Lombok (with specific configurations)
- Validation: Jakarta Bean Validation
- Serialization: Jackson (with custom modules for strict xAPI compliance)
# Clean build with tests
./mvnw clean verify
# Build without tests
./mvnw clean verify -DskipTestsAlways run the full build before starting work to ensure you understand the current state:
./mvnw clean verifyAlways run the full build after making changes to ensure your changes don't break the build:
./mvnw clean verify- Strictly follow the Google Java Style Guide
IMPORTANT: All Java code must be formatted using the Spotify fmt-maven-plugin before committing:
./mvnw com.spotify.fmt:fmt-maven-plugin:format- Run this command after making code changes and before committing
- The formatter automatically applies Google Java Style formatting
- A git pre-commit hook is available via
./install-git-hooks.shto automate this
- CheckStyle validation runs automatically during Maven build
- Over 300 unit tests ensure xAPI specification conformance
All xAPI model objects are immutable and use a fluent interface pattern:
Statement statement = Statement.builder()
.agentActor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
.verb(Verb.ATTEMPTED)
.activityObject(o -> o.id("https://example.com/activity/simplestatement")
.definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))
.build();Use toBuilder() to create modified versions of immutable objects:
Statement completedStatement = attemptedStatement.toBuilder()
.verb(Verb.COMPLETED)
.build();- All model classes use Lombok for reducing boilerplate
- Common annotations:
@Builder,@Value,@Getter,@With - Lombok config is set in
lombok.configfiles - Constructor properties are added for deserialization compatibility
Models use Jakarta Bean Validation annotations:
@NotNullfor required fields- Custom validators in
dev.learning.xapi.model.validation.constraints - Validation can be programmatically executed or automatic in Spring controllers with
@Valid
Custom Jackson modules provide strict xAPI compliance:
XapiStrictLocaleModule: Validates locale formatsXapiStrictNullValuesModule: Handles null value validationXapiStrictObjectTypeModule: Validates objectType fieldsXapiStrictTimestampModule: Validates timestamp formats
- Tests use JUnit 5 (
@Test,@DisplayName) - Hamcrest matchers for assertions (
assertThat,is,notNullValue, etc.) - JSON path matchers for verifying serialization:
hasJsonPath,hasNoJsonPath
@Test
@DisplayName("When Statement Has All Properties Then Serialization Works")
void testStatementSerialization() throws JsonProcessingException {
Statement statement = Statement.builder()
.agentActor(a -> a.name("Test User").mbox("mailto:test@example.com"))
.verb(Verb.COMPLETED)
.activityObject(o -> o.id("https://example.com/activity/1"))
.build();
String json = objectMapper.writeValueAsString(statement);
assertThat(json, hasJsonPath("$.actor.name", is("Test User")));
assertThat(json, hasJsonPath("$.verb.id"));
}- Comprehensive unit tests for all model classes
- Integration tests for client functionality
- Tests verify xAPI specification compliance
- Use MockWebServer (OkHttp) for testing HTTP interactions in xapi-client
- Tests use Given When Then pattern or When Then if there is no current state.
- Contains all xAPI data model classes (Statement, Actor, Verb, Activity, etc.)
- All classes are immutable with builder pattern
- Extensive validation annotations
- Custom validators for xAPI-specific rules
- Located in
xapi-model/src/main/java/dev/learning/xapi/model/
- Spring WebClient-based reactive client
- Implements xAPI Statement, State, Agent Profile, and Activity Profile resources
- Auto-configuration via Spring Boot
- Uses fluent request builders
- Located in
xapi-client/src/main/java/dev/learning/xapi/client/
- Provides Spring Boot autoconfiguration
- Configurable validation rules via properties (prefix:
xapi.model.) - All validation rules default to TRUE (strict mode)
- Located in
xapi-model-spring-boot-starter/src/main/java/
- Example applications demonstrating client usage
- Each sample shows a specific xAPI operation
- Use samples as reference for common patterns
- Located in
samples/directory - There is a simple learning record store that uses the xAPI model and implements a subset of the xAPI specification.
Agent agent = Agent.builder()
.name("John Doe")
.mbox("mailto:john.doe@example.com")
.build();Group group = Group.builder()
.name("Team A")
.addMember(m -> m.name("Member 1").mbox("mailto:member1@example.com"))
.addMember(m -> m.name("Member 2").mbox("mailto:member2@example.com"))
.build();LanguageMap names = LanguageMap.builder()
.addEntry(Locale.ENGLISH, "English Name")
.addEntry(Locale.FRENCH, "Nom Français")
.build();- All data must conform to the xAPI specification
- IRI/URI fields must include schemes (e.g.,
https://,mailto:) - Timestamps follow ISO 8601 format
- UUIDs must be variant 4
- Score values have specific ranges (-1 to 1 for scaled scores)
- Voided statements must reference other statements
When working with xapi-client:
- Default Spring WebClient buffer limit: 256KB
- May need to increase for large statement sets or attachments
- Configure via
spring.codec.max-in-memory-sizeproperty
- maven_push.yml: Runs on push to main (build, test, Sonar scan)
- maven_pull_request.yml: Runs on PRs (build, test, conditional Sonar scan)
- codeql.yml: Security scanning
- All builds must pass CheckStyle validation
- All tests must pass
- SonarCloud quality gate must pass
- CodeQL security checks must pass
- All source files include copyright header:
Copyright 2016-2025 Berry Cloud Ltd. All rights reserved. - Project is licensed under Apache License 2.0
- Maintain copyright headers when creating new files
- Read the xAPI specification when working with model classes
- Use existing patterns - the codebase has consistent patterns for builders, validation, and testing
- Write tests first - the project has excellent test coverage, maintain it
- Keep immutability - never add mutable state to model objects
- Follow fluent patterns - builders should support method chaining
- Validate strictly - default to strict xAPI compliance unless explicitly configured otherwise
- Document public APIs - use JavaDoc for public methods and classes
- Check samples - refer to sample applications for usage patterns
- README.md contains detailed usage examples
- Each module has comprehensive JavaDoc
- Samples folder demonstrates common use cases
- xAPI specification: https://github.com/adlnet/xAPI-Spec