Source code for ralph.guidelines.java

"""Java-specific review guideline categories.

Ported from the canonical Rust implementation in
``ralph-workflow/src/guidelines/java.rs`` and adapted for the Python port.
The module exposes a lightweight data container with optional Spring-specific
extensions for Java codebases.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from collections.abc import Iterable


[docs] @dataclass class JavaGuidelines: """Java language-specific review checks. Args: frameworks: Optional framework names used to add stack-specific guidance. """ frameworks: tuple[str, ...] = () quality_checks: list[str] = field(init=False) security_checks: list[str] = field(init=False) performance_checks: list[str] = field(init=False) testing_checks: list[str] = field(init=False) documentation_checks: list[str] = field(init=False) idioms: list[str] = field(init=False) anti_patterns: list[str] = field(init=False) concurrency_checks: list[str] = field(init=False) resource_checks: list[str] = field(init=False) observability_checks: list[str] = field(init=False) api_design_checks: list[str] = field(init=False) def __init__(self, frameworks: Iterable[str] = ()) -> None: normalized_frameworks = tuple(frameworks) self.frameworks = normalized_frameworks self.quality_checks = [ "Follow Java naming conventions.", "Use Optional instead of null returns where it clarifies absence.", "Prefer composition over inheritance.", "Use try-with-resources for AutoCloseable resources.", ] self.security_checks = [ "Use PreparedStatement or parameterized queries for SQL access.", "Validate deserialized objects before use.", "Check for path traversal in file operations.", ] self.performance_checks = [ "Avoid unnecessary object allocation in hot paths.", "Choose data structures and stream usage based on measured costs.", "Be explicit about blocking I/O and expensive database access.", ] self.testing_checks = [ "Cover service, repository, and controller behavior with focused tests.", "Test exception handling and validation failures, not only happy paths.", "Keep mocks at network, filesystem, and process boundaries.", ] self.documentation_checks = [ "Document public APIs and non-obvious business rules.", "Keep Javadoc aligned with actual parameters, return values, and exceptions.", "Explain transactional, threading, and framework-specific assumptions.", ] self.idioms = [ "Use interfaces and records where they simplify API boundaries and DTOs.", "Prefer immutable value objects when mutability is not required.", "Use standard library and framework conventions before custom abstractions.", ] self.anti_patterns = [ "Avoid catching Exception or Throwable.", "Do not use raw types with generics.", "Avoid public fields.", ] self.concurrency_checks = [ "Shared mutable state is synchronized consistently.", "Executor, CompletableFuture, and thread-pool usage has clear lifecycle management.", "Concurrent code does not block event loops or request threads unexpectedly.", ] self.resource_checks = [ "Connections, streams, and files are closed on success and failure paths.", "Database transactions, locks, and other managed resources have clear ownership.", "Long-lived caches and buffers have bounds and eviction strategy where needed.", ] self.observability_checks = [ "Errors are logged with enough context to diagnose failures.", "Security-relevant and state-changing operations have appropriate audit visibility.", "Logs avoid exposing secrets and personally identifiable information.", ] self.api_design_checks = [ "API naming is consistent across services, DTOs, and controller endpoints.", "Method contracts are explicit about nullability, exceptions, and side effects.", "Dependency injection boundaries stay clear and constructor-based where possible.", ] for framework in normalized_frameworks: self._apply_framework(framework) def _apply_framework(self, framework: str) -> None: """Add framework-specific guideline extensions.""" if framework.casefold() != "spring": return self.quality_checks.extend( [ "Use constructor injection.", "Follow Spring Boot conventions.", "Use proper transaction management.", ] ) self.security_checks.extend( [ "Configure Spring Security properly.", "Use @Valid for input validation.", ] ) self.testing_checks.extend( [ "Prefer focused slice tests before broad @SpringBootTest coverage.", "Verify controller validation, serialization, and security behavior.", ] ) self.api_design_checks.append( "Keep Spring annotations focused and avoid leaking framework concerns across layers." )
[docs] def summary(self) -> str: """Return a short human-readable summary.""" return ( f"{len(self.quality_checks)} quality checks, " f"{len(self.security_checks)} security checks, " f"{len(self.anti_patterns)} anti-patterns" )
[docs] def total_checks(self) -> int: """Return the total number of configured checks.""" return sum( [ len(self.quality_checks), len(self.security_checks), len(self.performance_checks), len(self.testing_checks), len(self.documentation_checks), len(self.idioms), len(self.anti_patterns), len(self.concurrency_checks), len(self.resource_checks), len(self.observability_checks), len(self.api_design_checks), ] )
__all__ = ["JavaGuidelines"]