Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat : upgrade to springboot 3.4 #1480

Merged
merged 3 commits into from
Nov 1, 2024
Merged

Conversation

rajadilipkolli
Copy link
Owner

@rajadilipkolli rajadilipkolli commented Nov 1, 2024

Summary by CodeRabbit

  • New Features

    • Introduced a ClientLoggerRequestInterceptor to log HTTP request and response details for better monitoring.
    • Added new configuration properties for HTTP client management, including connect and read timeouts.
    • Added a new property for managing external call URLs within the application.
  • Bug Fixes

    • Updated to the latest Spring Boot version, which may include various enhancements and fixes.
  • Chores

    • Removed outdated HTTP client configurations to streamline the setup.

Copy link
Contributor

coderabbitai bot commented Nov 1, 2024

Walkthrough

The changes in this pull request involve updates to the boot-restclient project, including a version upgrade in the pom.xml file for Spring Boot and the googleJavaFormat plugin. A new class, ClientLoggerRequestInterceptor, has been added to log HTTP requests and responses, replacing previous logging mechanisms. The RestClientConfiguration class has been modified to utilize this new interceptor and remove outdated HTTP client components. Additionally, new properties related to HTTP client configuration have been introduced in the application.properties file, along with a new configuration metadata file.

Changes

File Change Summary
httpClients/boot-restclient/pom.xml Updated Spring Boot parent version to 3.4.0-RC1 and googleJavaFormat plugin to 1.24.0.
httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/ClientLoggerRequestInterceptor.java Added ClientLoggerRequestInterceptor class to log HTTP requests/responses with a buffering wrapper.
httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/RestClientConfiguration.java Updated restClientCustomizer to use ClientLoggerRequestInterceptor; removed JDK client-related beans.
httpClients/boot-restclient/src/main/resources/application.properties Added properties for HTTP client configuration: spring.http.client.factory, connect-timeout, and read-timeout.
httpClients/boot-restclient/src/main/resources/META-INF/additional-spring-configuration-metadata.json Introduced new configuration metadata file with property application.external-call-url.
httpClients/boot-restclient/src/test/java/com/example/restclient/bootrestclient/services/PostServiceTest.java Updated test to include ClientLoggerRequestInterceptor in the test context and modified imports for clarity.

Poem

In the land of code where rabbits hop,
We've upgraded our tools, we won't stop!
Logging requests with style and grace,
A new interceptor takes its place.
With properties set, our clients are spry,
Hopping through requests, oh me, oh my! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@rajadilipkolli rajadilipkolli self-assigned this Nov 1, 2024
@github-actions github-actions bot added type: dependency-upgrade Pull requests that update a dependency file component: httpclients labels Nov 1, 2024
Copy link
Contributor

@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: 5

🧹 Outside diff range and nitpick comments (4)
httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/ClientLoggerRequestInterceptor.java (4)

47-59: Optimize logging format for readability

The use of long delimiter lines in logs can clutter the logging output and make it harder to read. Simplifying or removing excessive delimiters can improve log readability.

Consider adjusting the delimiter lines:

-        log.info(
-                "===========================request begin================================================");
+        log.info("=== Request Begin ===");

...

-        log.info(
-                "==========================request end================================================");
+        log.info("=== Request End ===");

61-64: Log headers in a consolidated format

Logging each header individually can produce excessive log entries. Consolidating headers into a single log statement can make logs cleaner.

Consider logging headers as a single map:

-        log.info("Headers     : ");
-        headers.forEach((name, values) -> values.forEach(value -> log.info("{}={}", name, value)));
+        log.info("Headers     : {}", headers);

18-105: Add JavaDoc comments to improve maintainability

Adding JavaDoc comments to public classes and methods enhances code readability and helps other developers understand the purpose and usage of the code.

Consider adding JavaDoc comments to the class and its public methods.


20-20: Use parameterized logging instead of string concatenation

Ensure that all logging statements use parameterized logging to prevent unnecessary string concatenation when the log level is not enabled.

Verify that all log.info statements are using placeholders {} with parameters, which is already correctly implemented.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 92ddb34 and d0fe553.

📒 Files selected for processing (4)
  • httpClients/boot-restclient/pom.xml (2 hunks)
  • httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/ClientLoggerRequestInterceptor.java (1 hunks)
  • httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/RestClientConfiguration.java (2 hunks)
  • httpClients/boot-restclient/src/main/resources/application.properties (1 hunks)
🔇 Additional comments (6)
httpClients/boot-restclient/src/main/resources/application.properties (2)

8-8: LGTM! Good choice using the JDK HTTP client.

The configuration aligns well with Spring Boot 3.4's recommended approach of using the JDK HTTP client.


9-10: Consider environment-specific timeout configurations.

While the timeout values are reasonable for development:

  • Connect timeout of 30s might be too long for production environments
  • Read timeout of 1m could be excessive for simple API calls

Consider defining different timeout values for different environments (dev/staging/prod) or specific endpoints.

Let's check if there are any environment-specific property files:

Recommendations:

  1. For production, consider shorter timeouts (e.g., connect: 5s, read: 30s)
  2. For critical endpoints, consider creating separate RestClient beans with custom timeouts
  3. Document the timeout values in your operational runbook
httpClients/boot-restclient/pom.xml (2)

75-75: LGTM: Google Java Format version update

The update to Google Java Format 1.24.0 is a safe improvement that brings the latest formatting rules and improvements.


8-8: Caution: Using Spring Boot RC version in production

The upgrade to Spring Boot 3.4.0-RC1 introduces potential risks as Release Candidate versions are not recommended for production use. Consider the following:

  • RC versions may contain breaking changes
  • Limited community testing and feedback
  • Potential compatibility issues with existing dependencies

Consider staying on the latest stable version (3.3.5) for production environments or ensure thorough testing if proceeding with the RC version.

Let's verify dependency compatibility:

httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/RestClientConfiguration.java (2)

38-38: Integration of ClientLoggerRequestInterceptor is correct

The addition of .requestInterceptor(clientLoggerRequestInterceptor) properly integrates the custom interceptor into the RestClient configuration, enhancing HTTP request logging.


26-26: Ensure ClientLoggerRequestInterceptor is a Spring Bean

Please confirm that ClientLoggerRequestInterceptor is properly declared as a Spring-managed bean. It should be annotated with @Component, @Service, or defined as a @Bean in a configuration class to enable dependency injection into restClientCustomizer.

Run the following script to verify:

✅ Verification successful

ClientLoggerRequestInterceptor is properly configured as a Spring Bean

The class is correctly annotated with @Component, making it a Spring-managed bean that can be autowired into RestClientConfiguration.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that ClientLoggerRequestInterceptor is declared as a Spring Bean.

# Search for the class file
fd 'ClientLoggerRequestInterceptor.java' | while read file; do
  # Check for Spring annotations in the class
  rg '@(Component|Service|Configuration)' "$file" && echo "Found Spring annotation in $file"
done

# Alternatively, check for @Bean methods returning ClientLoggerRequestInterceptor
rg '@Bean' -A 2 --type java | rg 'ClientLoggerRequestInterceptor'

Length of output: 613

Comment on lines 38 to 41
byte[] responseBody = response.getBody().readAllBytes();
if (responseBody.length > 0) {
log.info("Response body: {}", new String(responseBody, StandardCharsets.UTF_8));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle potential memory issues with large response bodies

Reading the entire response body into memory using readAllBytes() can lead to OutOfMemoryError if the response is large. This may affect the application's performance and stability.

Consider limiting the size of the response body that is read and logged, or stream the response body instead of loading it entirely into memory.

log.info("Status code : {}", response.getStatusCode());
log.info("Status text : {}", response.getStatusText());
logHeaders(response.getHeaders());
byte[] responseBody = response.getBody().readAllBytes();
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure response body stream is not consumed

Calling response.getBody().readAllBytes() consumes the input stream, which may cause issues for downstream processing that expects to read from the response body.

To prevent consuming the response body stream, consider wrapping the response without reading and consuming the stream upfront.

logHeaders(response.getHeaders());
byte[] responseBody = response.getBody().readAllBytes();
if (responseBody.length > 0) {
log.info("Response body: {}", new String(responseBody, StandardCharsets.UTF_8));
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid logging sensitive information in response bodies

Logging the response body can expose sensitive data returned by the server. This poses a security risk if the logs are compromised.

Apply this diff to remove logging of the response body:

-        if (responseBody.length > 0) {
-            log.info("Response body: {}", new String(responseBody, StandardCharsets.UTF_8));
-        }

Committable suggestion skipped: line range outside the PR's diff.

log.info("Method : {}", request.getMethod());
logHeaders(request.getHeaders());
if (body.length > 0) {
log.info("Request body: {}", new String(body, StandardCharsets.UTF_8));
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid logging sensitive information in request bodies

Logging the request body may expose sensitive data such as credentials or personal information. It's a security risk to log request bodies without sanitization.

Apply this diff to remove logging of the request body:

-        if (body.length > 0) {
-            log.info("Request body: {}", new String(body, StandardCharsets.UTF_8));
-        }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 70 to 73
public BufferingClientHttpResponseWrapper(ClientHttpResponse response, byte[] body) {
this.response = response;
this.body = body;
}
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 1, 2024

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Reuse existing classes for response buffering

Spring provides a BufferingClientHttpResponseWrapper class that can be used instead of implementing a custom wrapper. This reduces code duplication and leverages existing, well-tested functionality.

Consider replacing the custom BufferingClientHttpResponseWrapper with Spring's existing class.

Apply this diff:

-    private static class BufferingClientHttpResponseWrapper implements ClientHttpResponse {
-        // Custom implementation
-    }
+    // Remove custom wrapper and use Spring's BufferingClientHttpResponseWrapper

And modify the logResponse method accordingly.

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Owner Author

Choose a reason for hiding this comment

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

@coderabbitai, Spring's BufferingClientHttpResponseWrapper is not a public class, how to replace custom code with Spring's BufferingClientHttpResponseWrapper?

Copy link
Contributor

Choose a reason for hiding this comment

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

@rajadilipkolli, thank you for pointing that out. You are correct that Spring's BufferingClientHttpResponseWrapper is not a public class and cannot be used directly. In this case, your custom implementation is appropriate.


✏️ Learnings added
Learnt from: rajadilipkolli
PR: rajadilipkolli/my-spring-boot-experiments#1480
File: httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/ClientLoggerRequestInterceptor.java:70-73
Timestamp: 2024-11-01T10:48:43.983Z
Learning: Spring's `BufferingClientHttpResponseWrapper` is not public and cannot be used directly outside of the `org.springframework.http` package. Therefore, custom implementations are necessary when response buffering is needed in `ClientHttpResponse` interceptors.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Copy link

sonarqubecloud bot commented Nov 1, 2024

Copy link
Contributor

@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: 0

🧹 Outside diff range and nitpick comments (1)
httpClients/boot-restclient/src/main/resources/META-INF/additional-spring-configuration-metadata.json (1)

4-7: Enhance property documentation with additional metadata.

The current description could be more comprehensive to help users configure the property correctly.

Consider adding more detailed metadata:

 {
     "name": "application.external-call-url",
     "type": "java.lang.String",
-    "description": "URL to which call should be made."
+    "description": "Base URL for external service calls. Must be a valid URL including the scheme (e.g., 'https://api.example.com').",
+    "defaultValue": "http://localhost:8080",
+    "validation": {
+        "pattern": "^(http|https)://[^\\s/$.?#].[^\\s]*$"
+    }
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d0fe553 and 16569f7.

📒 Files selected for processing (3)
  • httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/ClientLoggerRequestInterceptor.java (1 hunks)
  • httpClients/boot-restclient/src/main/resources/META-INF/additional-spring-configuration-metadata.json (1 hunks)
  • httpClients/boot-restclient/src/test/java/com/example/restclient/bootrestclient/services/PostServiceTest.java (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/ClientLoggerRequestInterceptor.java
🔇 Additional comments (4)
httpClients/boot-restclient/src/main/resources/META-INF/additional-spring-configuration-metadata.json (1)

1-9: LGTM! Configuration metadata structure is correct.

The JSON structure follows Spring Boot's configuration metadata schema correctly, and the property is well-defined with appropriate type information.

httpClients/boot-restclient/src/test/java/com/example/restclient/bootrestclient/services/PostServiceTest.java (3)

4-6: LGTM! Import changes improve code clarity.

The change from wildcard imports to explicit imports for MockRestRequestMatchers methods enhances code readability and maintainability.

Also applies to: 9-9


Line range hint 31-56: LGTM! Test implementation remains compatible with Spring Boot 3.4.

The test method implementation using MockRestServiceServer and assertions are well-structured and compatible with the Spring Boot upgrade.


24-29: Verify test context initialization order.

While the addition of ClientLoggerRequestInterceptor is appropriate, please verify that:

  1. The initialization order of components is correct (especially since RestClientConfiguration might need to be initialized before the interceptor)
  2. All required components for the test context are included

Let's check the component dependencies:

✅ Verification successful

Based on the search results, I can now provide a definitive response about the test context initialization order:

The component initialization order is correct and all required components are included

The verification shows that:

  1. ClientLoggerRequestInterceptor is a simple @Component that implements ClientHttpRequestInterceptor for logging purposes
  2. RestClientConfiguration is properly configured with proxyBeanMethods = false and injects the interceptor as a dependency in its restClientCustomizer bean
  3. The test context includes all necessary components in a logical order:
    • PostService (main service)
    • HttpClientService (client service)
    • RestClientConfiguration (configuration)
    • ClientLoggerRequestInterceptor (interceptor)

The initialization order is correct because Spring automatically handles the dependency resolution, and the interceptor will be created before it's injected into the RestClientConfiguration bean. The proxyBeanMethods = false setting ensures efficient initialization without any proxy-related side effects.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check component dependencies and initialization requirements

# Look for @Configuration classes and their dependencies
ast-grep --pattern 'class $_ {
  @Configuration
  $$$
}'

# Look for @Bean methods in RestClientConfiguration that might use the interceptor
ast-grep --pattern 'class RestClientConfiguration {
  $$$
  @Bean
  $$$
}'

Length of output: 135


Script:

#!/bin/bash
# Let's try a different approach to analyze the components and their dependencies

# Search for RestClientConfiguration class implementation
rg -l "class RestClientConfiguration" --type java

# Search for ClientLoggerRequestInterceptor implementation
rg -l "class ClientLoggerRequestInterceptor" --type java

# Look for @Configuration and @Bean annotations in these files
rg "@(Configuration|Bean)" --type java -C 3

# Search for dependency injection or usage of ClientLoggerRequestInterceptor
rg "ClientLoggerRequestInterceptor" --type java -C 3

Length of output: 241080

@rajadilipkolli rajadilipkolli merged commit 4af9851 into main Nov 1, 2024
7 checks passed
@rajadilipkolli rajadilipkolli deleted the restclient-upgrade-sb branch November 1, 2024 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: httpclients type: dependency-upgrade Pull requests that update a dependency file
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant