| name | cui-java-core |
| description | Core Java development standards for CUI projects including coding patterns, null safety, Lombok, modern features, and logging |
| allowed-tools | Read, Edit, Write, Bash, Grep, Glob |
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:
Task: 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