CUI Java Core Development Skill
Foundational Java development standards for all CUI projects, covering core patterns, null safety, Lombok usage, modern Java features, and the CUI logging framework.
Workflow
Step 1: Load Core Java Standards
CRITICAL: Load all foundational Java standards (always required for Java development).
Read: standards/java-core-patterns.md Read: standards/java-null-safety.md Read: standards/java-lombok-patterns.md Read: standards/java-modern-features.md Read: standards/logging-standards.md
These standards are fundamental to all CUI Java development and should be loaded together for consistent, comprehensive guidance.
Step 2: Load Additional Knowledge (Optional)
When needed: Load domain-specific knowledge on demand.
DSL-Style Constants (load when needed):
Read: standards/dsl-constants.md
Use when: Implementing LogMessages classes, creating structured constant hierarchies, or needing guidance on organizing related constants with nested static classes and the @UtilityClass pattern.
LogMessages Documentation (load when needed):
Read: standards/logmessages-documentation.md
Use when: Writing or maintaining AsciiDoc documentation for LogMessages classes, or needing guidance on documenting log message standards.
CUI HTTP Client (load when needed):
Read: standards/cui-http.md
Use when: Working with HTTP client code, implementing HTTP request/response handling, or needing guidance on the HttpResult pattern, retry logic, ETag caching, or HTTP error handling.
Step 3: Extract Key Requirements
From all loaded standards, extract and organize:
- •
Core Patterns:
- •Code organization (packages, classes, methods)
- •Naming conventions
- •Exception handling patterns
- •Best practices for immutability and collections
- •Parameter object guidelines
- •
Null Safety:
- •@NullMarked package configuration
- •API return type patterns (non-null vs Optional)
- •Implementation requirements
- •Nullable parameter handling
- •
Lombok Patterns:
- •@Delegate for delegation over inheritance
- •@Builder for complex objects
- •@Value for immutable objects
- •When to use each annotation
- •
Modern Features:
- •Records for data carriers
- •Switch expressions
- •Stream processing patterns
- •Text blocks and pattern matching
- •Optional enhancements
- •
Logging:
- •CuiLogger configuration
- •LogRecord usage and organization
- •Log level guidelines
- •Exception logging patterns
Step 4: Analyze Existing Code (if applicable)
If working with existing Java code:
- •
Assess standards compliance:
- •Check null-safety annotations (@NullMarked in package-info.java)
- •Verify logger configuration (CuiLogger, not SLF4J)
- •Review Lombok usage (appropriate annotations)
- •Check for modern Java features (records, switch expressions)
- •Review exception handling patterns
- •
Identify improvement opportunities:
- •Missing null-safety annotations
- •Legacy logging (System.out, SLF4J annotations)
- •Inefficient patterns (deep inheritance, god classes)
- •Missing modern features (classic switch, manual data classes)
- •Verbose boilerplate that Lombok could handle
- •
Check code organization:
- •Package structure (feature-based)
- •Class responsibilities (Single Responsibility Principle)
- •Method sizes (< 50 lines preferred)
- •Parameter counts (≤ 3 preferred)
Step 5: Write/Refactor Java Code According to Standards
When writing or refactoring Java code:
- •
Apply core patterns:
- •Organize packages by feature
- •Keep classes focused and small
- •Use meaningful names throughout
- •Handle exceptions appropriately
- •Prefer immutability
- •Use parameter objects for 3+ parameters
- •
Implement null safety:
- •Add @NullMarked to package-info.java
- •Never use @Nullable for return types (use Optional instead)
- •Add defensive null checks at API boundaries
- •Use Objects.requireNonNull() for validation
- •Document null-safety contracts
- •
Use Lombok appropriately:
- •@Delegate for composition over inheritance
- •@Builder for classes with 3+ parameters or optional parameters
- •@Value for immutable value objects and DTOs
- •@UtilityClass for utility classes
- •Consider records vs @Value for simple data carriers
- •
Apply modern Java features:
- •Use records for simple immutable data carriers
- •Replace classic switch with switch expressions
- •Use streams for complex data transformations
- •Apply text blocks for multi-line strings
- •Use pattern matching for instanceof
- •Leverage modern collection factories (List.of(), Set.of())
- •
Implement CUI logging:
- •Declare logger:
private static final CuiLogger LOGGER = new CuiLogger(YourClass.class); - •Create LogMessages class for structured logging
- •Use LogRecord for INFO/WARN/ERROR/FATAL
- •Exception parameter always comes first
- •Use %s for all string substitutions
- •Organize identifiers by log level ranges
- •Declare logger:
Step 6: Verify Standards Compliance
Before completing the task:
- •
Core patterns check:
- • Classes follow Single Responsibility Principle
- • Methods are short and focused (< 50 lines)
- • Meaningful names used throughout
- • Exception handling is appropriate
- • Immutability used where possible
- • No magic numbers or god classes
- •
Null safety check:
- • @NullMarked in package-info.java
- • No @Nullable used for return types
- • Optional used for "no result" scenarios
- • Defensive null checks at API boundaries
- • Unit tests verify non-null contracts
- •
Lombok check:
- • @Builder used for complex construction
- • @Value used for immutable objects
- • @Delegate used for composition
- • No @Slf4j or logging annotations (use CuiLogger)
- •
Modern features check:
- • Records used for simple data carriers
- • Switch expressions used instead of statements
- • Streams used appropriately
- • Text blocks used for multi-line strings
- • Modern collection factories used
- •
Logging check:
- • CuiLogger used (not SLF4J/Log4j)
- • Logger is private static final named LOGGER
- • LogRecord used for important messages
- • Exception parameter comes first
- • %s used for substitutions
- • No System.out or System.err
- •
Run build and tests:
codeTask: subagent_type: maven-builder description: Build and verify project prompt: | Execute Maven build to verify all tests pass and code compiles correctly. Parameters: - command: clean verify CRITICAL: Wait for build to complete. Inspect results and respond to any failures.
Step 7: Report Results
Provide summary of:
- •Standards applied: Which core Java standards were followed
- •Code improvements: Changes made to align with standards
- •Null safety: Package-level @NullMarked and Optional usage
- •Lombok usage: Which annotations were applied and why
- •Modern features: Records, switch expressions, streams implemented
- •Logging: CuiLogger and LogRecord implementation
- •Build verification: Confirm successful build and test execution
Common Patterns and Examples
Complete Class Example
// package-info.java
@NullMarked
package de.cuioss.portal.authentication;
import org.jspecify.annotations.NullMarked;
// TokenValidator.java
import de.cuioss.tools.logging.CuiLogger;
import static de.cuioss.portal.authentication.TokenLogMessages.INFO;
import static de.cuioss.portal.authentication.TokenLogMessages.ERROR;
@Value
@Builder
public class TokenValidator {
private static final CuiLogger LOGGER = new CuiLogger(TokenValidator.class);
String issuer;
@Builder.Default
Duration validity = Duration.ofHours(1);
public ValidationResult validate(String token) {
Objects.requireNonNull(token, "token must not be null");
try {
String userId = extractUserId(token);
boolean isValid = performValidation(token);
if (isValid) {
LOGGER.info(INFO.VALIDATION_SUCCESS, userId);
return ValidationResult.valid();
}
LOGGER.error(ERROR.VALIDATION_FAILED, userId, "Invalid signature");
return ValidationResult.invalid("Invalid signature");
} catch (TokenException e) {
LOGGER.error(e, ERROR.VALIDATION_FAILED, "unknown", e.getMessage());
throw new ValidationException("Validation failed", e);
}
}
public Optional<UserInfo> extractUserInfo(String token) {
return parseToken(token).map(this::extractUser);
}
}
LogMessages Example
@UtilityClass
public final class TokenLogMessages {
public static final String PREFIX = "TOKEN";
@UtilityClass
public static final class INFO {
public static final LogRecord VALIDATION_SUCCESS = LogRecordModel.builder()
.template("Token validated successfully for user %s")
.prefix(PREFIX)
.identifier(1)
.build();
}
@UtilityClass
public static final class ERROR {
public static final LogRecord VALIDATION_FAILED = LogRecordModel.builder()
.template("Token validation failed for user %s: %s")
.prefix(PREFIX)
.identifier(200)
.build();
}
}
Record with Validation Example
public record TokenConfig(String issuer, Duration validity, Set<String> requiredClaims) {
public TokenConfig {
Objects.requireNonNull(issuer, "issuer must not be null");
Objects.requireNonNull(validity, "validity must not be null");
if (validity.isNegative() || validity.isZero()) {
throw new IllegalArgumentException("Validity must be positive");
}
requiredClaims = Set.copyOf(requiredClaims); // Defensive copy
}
public static TokenConfig defaultConfig() {
return new TokenConfig(
"https://auth.example.com",
Duration.ofHours(1),
Set.of("sub", "exp")
);
}
}
Delegation Example
public class CachedTokenValidator implements TokenValidator {
@Delegate
private final TokenValidator delegate;
private final Cache<String, ValidationResult> cache;
public CachedTokenValidator(TokenValidator delegate) {
this.delegate = delegate;
this.cache = CacheBuilder.newBuilder()
.expireAfterWrite(Duration.ofMinutes(5))
.build();
}
@Override
public ValidationResult validate(String token) {
return cache.get(token, () -> delegate.validate(token));
}
}
Switch Expression Example
ValidationResult validate(Token token) {
return switch (token.getType()) {
case JWT -> jwtValidator.validate(token);
case OAUTH2 -> oauth2Validator.validate(token);
case LEGACY -> ValidationResult.invalid("Legacy tokens not supported");
};
}
Stream Processing Example
List<String> activeUserNames = users.stream()
.filter(User::isActive)
.map(User::getName)
.sorted()
.toList();
Map<String, List<User>> usersByRole = users.stream()
.collect(Collectors.groupingBy(User::getRole));
Common Development Tasks
Task: Create a new service class
- •Load all core Java standards
- •Add @NullMarked to package-info.java
- •Define class with appropriate Lombok annotations (@Value/@Builder if immutable)
- •Declare CuiLogger
- •Create LogMessages class following DSL pattern
- •Implement methods with proper null safety
- •Use modern Java features (records for DTOs, switch expressions, streams)
- •Write unit tests verifying behavior
- •Run build using maven-builder agent
Task: Refactor existing code to standards
- •Load all core Java standards
- •Add @NullMarked to package-info.java if missing
- •Replace SLF4J/Log4j with CuiLogger
- •Apply Lombok where appropriate (@Builder, @Value, @Delegate)
- •Replace classic patterns with modern features (records, switch expressions)
- •Add null checks at API boundaries
- •Update tests to verify compliance
- •Run build and verify no regressions
Task: Add comprehensive logging
- •Load logging standards and DSL constants standards
- •Create LogMessages class with DSL-style nested structure
- •Define LogRecord for each important message
- •Organize by log level (INFO, WARN, ERROR, FATAL)
- •Use correct identifier ranges
- •Apply static imports in service classes
- •Use LogRecord with proper exception handling
- •Add test verification for log messages
- •Verify no System.out or System.err usage
Error Handling
If encountering issues:
- •Null pointer exceptions: Review null-safety implementation, add @NullMarked and defensive checks
- •Lombok not working: Check Lombok dependency, IDE plugin, and annotation placement
- •Logger errors: Verify CuiLogger setup, check exception parameter order and %s usage
- •Build failures: Check modern Java feature compatibility with target Java version
- •Complex refactoring: Break into smaller steps, focus on one standard at a time
References
Core Standards (always loaded):
- •Core Patterns: standards/java-core-patterns.md
- •Null Safety: standards/java-null-safety.md
- •Lombok Patterns: standards/java-lombok-patterns.md
- •Modern Features: standards/java-modern-features.md
- •Logging: standards/logging-standards.md
Optional Standards (load when needed):
- •DSL Constants: standards/dsl-constants.md
- •LogMessages Documentation: standards/logmessages-documentation.md
- •CUI HTTP Client: standards/cui-http.md