Skip to content

Conversation

@juherr
Copy link
Owner

@juherr juherr commented Oct 12, 2025

Summary by CodeRabbit

  • New Features

    • Introduced an OICP 2.3 gateway module.
    • Added REST endpoints for EVSE data and status retrieval.
    • Added authorization start/stop endpoints.
    • Added charging notifications and charge detail record handling.
    • Unified success/error responses with consistent status codes.
    • Endpoints are enabled via configuration toggle.
  • Chores

    • Updated build configuration to include the new gateway module and generate API artifacts from OpenAPI specifications.

@coderabbitai
Copy link

coderabbitai bot commented Oct 12, 2025

Walkthrough

Adds a new steve-oicp gateway module, configures OpenAPI code generation for OICP 2.3 server/client, introduces an OCPP→OICP adapter, and exposes REST controllers for authorization, EVSE data/status, and charging notifications. Root POM references the new module and adjusts plugin versioning.

Changes

Cohort / File(s) Summary of changes
Build & modules
pom.xml
Added module steve-gateway/steve-oicp. Removed explicit spotless-maven-plugin version tag.
OICP module POM
steve-gateway/steve-oicp/pom.xml
Added dependencies (steve-core, Spring Web/Validation, Jackson JSR310, Swagger annotations, tests). Configured openapi-generator with executions for Spring server (EMP 2.3) and Java client (CPO 2.3), outputting generated sources and packages.
OICP response utility
steve-gateway/steve-oicp/src/main/java/.../oicp/OicpResponse.java
New utility with helpers: toResponse, successCode, errorCode.
OCPP→OICP adapter
steve-gateway/steve-oicp/src/main/java/.../oicp/adapter/OcppToOicpAdapter.java
New service mapping OCPP domain to OICP v2.3: EVSE data/status retrieval, authorize start/stop, charging notifications, CDR processing; includes internal conversion helpers and fallbacks.
OICP controllers
steve-gateway/steve-oicp/src/main/java/.../oicp/controller/AuthorizationController.java, .../ChargingNotificationsController.java, .../EvseDataController.java, .../EvseStatusController.java
New REST controllers implementing generated OICP APIs; delegate to adapter; conditional on property steve.gateway.enabled; structured error handling using OicpResponse helpers. Some endpoints marked unsupported.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor CPO as OICP Client (CPO/EMP)
  participant API as OICP REST Controller
  participant AD as OcppToOicpAdapter
  participant REPO as Core Repos/Services

  rect rgb(240,245,255)
  note over CPO,API: EVSE Data Pull (v2.3)
  CPO->>API: eRoamingPullEvseDataV23(providerID, request)
  API->>AD: getEVSEData(providerID, request)
  AD->>REPO: Fetch charge point overviews
  REPO-->>AD: Overviews + connectors
  AD-->>API: ERoamingEVSEData
  API-->>CPO: 200 OK (ERoamingEVSEData)
  end

  rect rgb(240,255,240)
  note over CPO,API: EVSE Status Pull (v2.1)
  CPO->>API: eRoamingPullEvseStatusV21(providerID, request)
  API->>AD: getEVSEStatus(providerID, request)
  AD->>REPO: Fetch connector statuses
  REPO-->>AD: Status DTOs
  AD-->>API: ERoamingPullEvseStatusV21200Response
  API-->>CPO: 200 OK (Status)
  end

  rect rgb(255,250,240)
  note over CPO,API: Authorization Start
  CPO->>API: eRoamingAuthorizeStartV21(request)
  API->>AD: authorizeStart(request)
  AD->>REPO: Validate RFID/tag
  REPO-->>AD: Tag state
  AD-->>API: ERoamingAuthorizationStart (AUTHORIZED/NOT_AUTHORIZED)
  API-->>CPO: 200 OK (Result)
  end

  rect rgb(255,240,245)
  note over CPO,API: Charging Notifications / CDR
  CPO->>API: eRoamingChargingNotificationsV11(request)
  API->>AD: processChargingNotification(request)
  AD-->>API: ERoamingAcknowledgment (true/false)
  API-->>CPO: 200 OK (Ack)

  CPO->>API: eRoamingChargeDetailRecordV22(cdr)
  API->>AD: processChargeDetailRecord(cdr)
  AD-->>API: ERoamingAcknowledgment
  API-->>CPO: 200 OK (Ack)
  end

  opt Error path
    API-->>CPO: 200 OK with StatusCode(code=3000/4000) and result=false
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

A hop, a skip, a gateway bright,
I nibble specs by moonlit night.
From OCPP to OICP, I weave the thread,
Controllers squeak and adapters tread.
With OpenAPI carrots in my pack,
I bound through endpoints—thump! I’m back.
Success code “000”? Twitch-tastic snack! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.39% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title “OICP support” directly reflects the primary purpose of the changeset, which is to introduce comprehensive OICP functionality into the gateway module, and is both concise and specific enough for reviewers to understand the main change at a glance.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch features/oicp

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (6)
pom.xml (1)

315-364: Pin the Spotless plugin version.

We previously hard-pinned spotless-maven-plugin. Dropping the <version> now makes builds depend on whichever release Maven resolves at runtime, which risks sudden breakages when upstream publishes a new major. Please restore the explicit version (or manage it in <pluginManagement>).

steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/adapter/OcppToOicpAdapter.java (3)

145-203: Avoid masking exceptions with generic catch.

The catch block at line 195 catches all exceptions and converts them to NOT_AUTHORIZED responses. This could hide programming errors (NPE, IllegalStateException, etc.) that should be logged differently or allowed to propagate.

Consider catching only expected exceptions (e.g., repository access failures) and letting unexpected ones bubble up to be handled by a global exception handler.


217-236: Complete the TODO for notification handling.

Line 229's TODO indicates different notification types should be handled differently, but currently all types are just acknowledged. For production, you'll need to implement actual processing logic for start, end, progress, and error notifications.

This appears to be a stub implementation. Do you want me to open an issue to track implementing the actual notification handling logic?


255-280: Add null-safe handling for missing charge point details.

Line 259 uses orElseThrow() without a descriptive exception. If getDetails() returns empty, this throws a generic NoSuchElementException that doesn't clearly indicate the charge point details are missing.

Apply this diff to provide a clearer exception:

-        var details =
-                chargePointRepository.getDetails(chargePoint.getChargeBoxPk()).orElseThrow();
+        var details = chargePointRepository.getDetails(chargePoint.getChargeBoxPk())
+                .orElseThrow(() -> new IllegalStateException(
+                        "Charge point details not found for ID: " + chargePoint.getChargeBoxId()));
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/OicpResponse.java (1)

26-38: Add private constructor to prevent instantiation.

This is a utility class with only static methods, but lacks a private constructor. While not critical, adding one prevents accidental instantiation and clearly signals the class's intent.

Apply this diff:

 public class OicpResponse {
+    private OicpResponse() {
+        throw new UnsupportedOperationException("Utility class");
+    }
+
     public static <T> ResponseEntity<T> toResponse(T data) {
         return ResponseEntity.of(Optional.of(data));
     }
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/AuthorizationController.java (1)

56-66: Document unsupported operations.

These methods throw UnsupportedOperationException for operations not yet implemented. Consider adding a comment or logging to clarify whether these are planned features or intentionally excluded from the initial OICP support.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 03b3259 and 91ecd8b.

📒 Files selected for processing (8)
  • pom.xml (1 hunks)
  • steve-gateway/steve-oicp/pom.xml (1 hunks)
  • steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/OicpResponse.java (1 hunks)
  • steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/adapter/OcppToOicpAdapter.java (1 hunks)
  • steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/AuthorizationController.java (1 hunks)
  • steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/ChargingNotificationsController.java (1 hunks)
  • steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/EvseDataController.java (1 hunks)
  • steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/EvseStatusController.java (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/src/{main,test}/java/**/*.java

📄 CodeRabbit inference engine (AGENTS.md)

Run Spotless and keep Java source formatted according to spotless-maven-plugin before committing (./mvnw spotless:apply).

Files:

  • steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/ChargingNotificationsController.java
  • steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/AuthorizationController.java
  • steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/EvseDataController.java
  • steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/EvseStatusController.java
  • steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/adapter/OcppToOicpAdapter.java
  • steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/OicpResponse.java
🧠 Learnings (1)
📚 Learning: 2025-09-29T19:19:47.728Z
Learnt from: CR
PR: juherr/evolve#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T19:19:47.728Z
Learning: Applies to **/src/{main,test}/java/**/*.java : Run Spotless and keep Java source formatted according to spotless-maven-plugin before committing (./mvnw spotless:apply).

Applied to files:

  • pom.xml
🧬 Code graph analysis (5)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/ChargingNotificationsController.java (5)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/adapter/OcppToOicpAdapter.java (1)
  • Slf4j (74-342)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/AuthorizationController.java (1)
  • Slf4j (48-125)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/EvseDataController.java (1)
  • Slf4j (39-60)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/EvseStatusController.java (1)
  • Slf4j (40-62)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/OicpResponse.java (1)
  • OicpResponse (26-38)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/AuthorizationController.java (2)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/adapter/OcppToOicpAdapter.java (1)
  • Slf4j (74-342)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/OicpResponse.java (1)
  • OicpResponse (26-38)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/EvseDataController.java (3)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/adapter/OcppToOicpAdapter.java (1)
  • Slf4j (74-342)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/EvseStatusController.java (1)
  • Slf4j (40-62)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/OicpResponse.java (1)
  • OicpResponse (26-38)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/EvseStatusController.java (2)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/adapter/OcppToOicpAdapter.java (1)
  • Slf4j (74-342)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/OicpResponse.java (1)
  • OicpResponse (26-38)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/adapter/OcppToOicpAdapter.java (6)
steve-core/src/main/java/de/rwth/idsg/steve/repository/dto/ChargePoint.java (1)
  • ChargePoint (33-86)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/AuthorizationController.java (1)
  • Slf4j (48-125)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/ChargingNotificationsController.java (1)
  • Slf4j (39-62)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/EvseDataController.java (1)
  • Slf4j (39-60)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/EvseStatusController.java (1)
  • Slf4j (40-62)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/OicpResponse.java (1)
  • OicpResponse (26-38)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: build (25, mariadb:10.5.21)
  • GitHub Check: build (25, mariadb:10.6.14)
  • GitHub Check: build (25, mariadb:10.4.30)
  • GitHub Check: build (21, mariadb:10.6.14)
  • GitHub Check: build (21, mysql:8.0)
  • GitHub Check: build (25, mariadb:10.3)
  • GitHub Check: build (21, mariadb:10.5.21)
  • GitHub Check: build (25, mysql:8.0)
  • GitHub Check: build (21, mariadb:10.3)
  • GitHub Check: build (21, mariadb:10.4.30)
🔇 Additional comments (10)
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/adapter/OcppToOicpAdapter.java (3)

205-214: Authorization stop needs validation logic.

This method unconditionally returns AUTHORIZED without any validation. In a real scenario, you should verify the session exists and the stop request is valid.

Is this intentionally stubbed for the initial implementation, or should it include validation similar to authorizeStart?


238-252: CDR processing is incomplete.

This method only logs the charge detail record but doesn't persist or process it. For OICP compliance, CDRs typically need to be stored for billing and reconciliation purposes.

Is this intentionally deferred, or should CDR persistence be implemented now?


329-341: LGTM: Status mapping is correct.

The OCPP to OICP status mapping logic correctly handles null input and uses case-insensitive comparison for string matching. The mapping choices are appropriate for the OICP standard.

steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/EvseDataController.java (1)

39-60: LGTM: Clean controller implementation.

The controller follows Spring best practices with proper conditional loading, dependency injection, error handling, and logging. The error handling correctly wraps exceptions and returns appropriate OICP error responses.

steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/ChargingNotificationsController.java (1)

39-62: LGTM: Consistent controller pattern.

The implementation follows the same clean pattern as other controllers in this PR, with proper error handling and logging. The delegation to the adapter is correct.

steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/EvseStatusController.java (1)

40-62: LGTM: Well-structured controller.

The controller correctly implements the EVSE status endpoint with proper error handling and logging, consistent with other controllers in this module.

steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/controller/AuthorizationController.java (4)

68-84: LGTM: Proper authorization start handling.

The endpoint correctly delegates to the adapter with appropriate error handling. The fallback error response (code 6000) is reasonable for authorization failures.


86-101: LGTM: Clean authorization stop implementation.

The implementation follows the same pattern as authorization start with consistent error handling and logging.


103-118: LGTM: CDR endpoint properly implemented.

The charge detail record endpoint correctly delegates processing to the adapter with appropriate error handling (code 4000 for processing failures).


120-125: Unsupported CDR retrieval operation.

Similar to remote start/stop, this method throws UnsupportedOperationException. Consider whether retrieving charge detail records should be part of the initial OICP implementation.

Is CDR retrieval functionality planned for a future iteration?

Comment on lines +36 to +43
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations-jakarta</artifactId>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.2.38</version>
</dependency>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Remove duplicated Swagger annotations dependency.

Both swagger-annotations-jakarta and swagger-annotations ship the exact same classes (io.swagger.v3.oas.annotations.*). With the global <banDuplicateClasses findAllDuplicates="true"/>, the build will now fail. Keep only the Jakarta artifact (needed for Spring Boot 3) and drop the vanilla swagger-annotations.

🤖 Prompt for AI Agents
In steve-gateway/steve-oicp/pom.xml around lines 36 to 43, there is a duplicated
Swagger annotations dependency causing duplicate-class failures; remove the
<dependency> block for io.swagger.core.v3:swagger-annotations (the non-Jakarta
artifact) and keep only the swagger-annotations-jakarta dependency required for
Spring Boot 3, updating the pom so only the jakarta artifact remains and no
duplicate classes are declared.

Comment on lines +83 to +106
public ERoamingEVSEData getEVSEData(String providerID, ERoamingPullEVSEData request) {
log.debug("Converting charge points to OICP EVSE data for provider: {}", providerID);

var form = new ChargePointQueryForm();
// TODO update form based on request filters

var evseDataList = chargePointRepository.getOverview(form).stream()
.map(this::convertChargePointToEVSEData)
.filter(Objects::nonNull)
.toList();

log.debug("Converted {} charge point overview to OICP EVSE data records", evseDataList.size());
return ERoamingEVSEData.builder()
.statusCode(successCode())
.content(evseDataList)
.size(evseDataList.size())
.numberOfElements(evseDataList.size())
.first(true)
.last(true)
.number(0)
.totalElements(evseDataList.size())
.totalPages(1)
.build();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Complete the TODO and implement pagination properly.

The EVSE data retrieval has two issues:

  1. Request filters are not applied (line 87 TODO)
  2. Pagination metadata is hardcoded (lines 100-104), returning all data as a single page regardless of actual dataset size

For large deployments, this could cause performance issues and memory pressure.

Would you like me to generate a verification script to check if there are existing pagination utilities in the codebase that could be leveraged here?

🤖 Prompt for AI Agents
In
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/adapter/OcppToOicpAdapter.java
around lines 83 to 106, the ChargePointQueryForm is not populated from the
ERoamingPullEVSEData request and pagination metadata is hardcoded; populate the
form with filtering values from the request (providerID, geographic/time
filters, status/type, and any other supported fields) and implement proper
pagination by reading page and size from the request (or sensible defaults),
then query the repository using a paginated API if available (preferred) or
apply stream skip/limit to the full result if not; compute totalElements from
the repository/count query, derive totalPages = ceil(totalElements/size), set
number = page, size = pageSize, numberOfElements = actual returned list size,
first = page == 0, last = page >= totalPages - 1, and fill those calculated
values into the ERoamingEVSEData builder instead of the current hardcoded
values.

Comment on lines +108 to +142
public ERoamingPullEvseStatusV21200Response getEVSEStatus(
String providerID, ERoamingPullEvseStatusV21Request request) {
log.debug("Getting EVSE status for provider: {}", providerID);

var form = new ConnectorStatusForm();
// TODO update form based on request filters
switch (request) {
case ERoamingPullEVSEStatus status -> {
// Handle ERoamingPullEVSEStatus specific logic
// For now, no specific filters are applied
}
case ERoamingPullEVSEStatusByID byId -> {
// Handle ERoamingPullEVSEStatusByID specific logic
// For now, no specific filters are applied
}
case ERoamingPullEVSEStatusByOperatorID byOperatorId -> {
// Handle ERoamingPullEVSEStatusByOperatorID specific logic
// For now, no specific filters are applied
}
default -> throw new IllegalArgumentException("Unknown request type: " + request.getClass());
}

var statusRecords = chargePointRepository.getChargePointConnectorStatus(form).stream()
.map(OcppToOicpAdapter::convertConnectorStatusToEVSEStatus)
.filter(Objects::nonNull)
.toList();

log.debug("Converted {} connector statuses to OICP EVSE status records", statusRecords.size());
return ERoamingEVSEStatusByID.builder()
.statusCode(successCode())
.evSEStatusRecords(ERoamingEVSEStatusByIDEVSEStatusRecords.builder()
.evseStatusRecord(statusRecords)
.build())
.build();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Implement request type filtering.

The switch statement (lines 114-128) has empty cases for all three request types, and the TODO at line 113 indicates filters are not yet applied. This means all three request variants return identical unfiltered results, which defeats their purpose.

🤖 Prompt for AI Agents
In
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/adapter/OcppToOicpAdapter.java
around lines 108-142, the switch over request types is empty so all variants
return the same unfiltered results; populate the ConnectorStatusForm inside each
case: for ERoamingPullEVSEStatus leave form unfiltered (global), for
ERoamingPullEVSEStatusByID extract the EVSE/connector IDs from the byId request
and set them on the form (single or list as appropriate), and for
ERoamingPullEVSEStatusByOperatorID set the operatorId on the form; validate
null/empty inputs before setting fields and ensure the repository call uses the
updated form so each request variant returns the correct filtered records.

Comment on lines +282 to +293
private static @Nullable AddressIso19773 convertAddress(ChargePoint.@Nullable Details addressRecord) {
if (addressRecord == null) {
return null;
}

return AddressIso19773.builder()
.country(addressRecord.getCountry().getName())
.city(addressRecord.getCity())
.street(addressRecord.getStreet())
.postalCode(addressRecord.getZipCode())
.build();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential NPE if country is null.

Line 288 calls addressRecord.getCountry().getName() which could throw NPE if country is null. Based on the ChargePoint.Details definition, country is of type CountryCode and may be nullable.

Add a null check for country or handle the case where address data is incomplete:

 private static @Nullable AddressIso19773 convertAddress(ChargePoint.@Nullable Details addressRecord) {
     if (addressRecord == null) {
         return null;
     }
+    if (addressRecord.getCountry() == null) {
+        return null;
+    }

     return AddressIso19773.builder()
             .country(addressRecord.getCountry().getName())
             .city(addressRecord.getCity())
             .street(addressRecord.getStreet())
             .postalCode(addressRecord.getZipCode())
             .build();
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private static @Nullable AddressIso19773 convertAddress(ChargePoint.@Nullable Details addressRecord) {
if (addressRecord == null) {
return null;
}
return AddressIso19773.builder()
.country(addressRecord.getCountry().getName())
.city(addressRecord.getCity())
.street(addressRecord.getStreet())
.postalCode(addressRecord.getZipCode())
.build();
}
private static @Nullable AddressIso19773 convertAddress(ChargePoint.@Nullable Details addressRecord) {
if (addressRecord == null) {
return null;
}
if (addressRecord.getCountry() == null) {
return null;
}
return AddressIso19773.builder()
.country(addressRecord.getCountry().getName())
.city(addressRecord.getCity())
.street(addressRecord.getStreet())
.postalCode(addressRecord.getZipCode())
.build();
}
🤖 Prompt for AI Agents
In
steve-gateway/steve-oicp/src/main/java/de/rwth/idsg/steve/gateway/oicp/adapter/OcppToOicpAdapter.java
around lines 282 to 293, the call to addressRecord.getCountry().getName() can
NPE when country is null; guard against a null country before calling getName()
and pass null (or an empty string if preferred) into the
AddressIso19773.builder(). For example, compute a countryName variable that is
addressRecord.getCountry() != null ? addressRecord.getCountry().getName() : null
and use that in the builder so the method safely handles incomplete address
records.

@juherr
Copy link
Owner Author

juherr commented Oct 12, 2025

@fmandache Based on your work, I’ve implemented these changes. From what I can tell, several parts of the business logic and some mandatory controllers are still missing. Is there a specific reason for these omissions?

@goekay Fyi.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants