Skip to content

Add tutorial using composite Id with Data REST #252

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

Merged
merged 9 commits into from
Jul 13, 2025

Conversation

rashidi
Copy link
Owner

@rashidi rashidi commented Jul 13, 2025

No description provided.

@rashidi rashidi added the enhancement New feature or request label Jul 13, 2025
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @rashidi, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a new, self-contained tutorial demonstrating best practices for integrating Spring Data REST with entities that utilize composite primary keys. The changes encompass new entity definitions, custom ID converters, and comprehensive integration tests, providing a clear example for developers facing similar challenges.

Highlights

  • New Tutorial Project: I've added a new tutorial project, data-rest-composite-id, which demonstrates how to implement and expose entities with composite IDs through Spring Data REST.
  • Entity Modeling with Composite IDs: The tutorial showcases two entity types, Author and Book, both utilizing @EmbeddedId for their primary keys. Author uses a simple Long wrapped in an embedded Id class, while Book uses a more complex Isbn class that parses an ISBN string into its components.
  • Spring Data REST ID Conversion: To properly handle composite IDs in the REST API, I've implemented BackendIdConverter for both Author.Id and Book.Isbn. Additionally, an AuthorIdReferencedConverter is registered to manage conversions when referencing Author entities by their composite ID.
  • Comprehensive Testing: The new tutorial includes integration tests (CreateAuthorTests, CreateBookTests, GetBookTests) to validate the creation and retrieval of entities with composite IDs via the exposed REST endpoints, utilizing Testcontainers for a robust testing environment.
  • Documentation Updates: The main README.adoc and the project's navigation (docs/modules/ROOT/nav.adoc) have been updated to include the new 'Spring Data REST with Composite ID' tutorial, with a dedicated data-rest-composite-id.adoc file providing detailed explanations.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds a new tutorial demonstrating how to use Spring Data REST with composite IDs. The changes include a new Spring Boot module with entities, repositories, converters, and tests, along with corresponding documentation.

The review identified several issues:

  • A mis-generated Liquibase file with duplicate changesets.
  • Potential NullPointerExceptions in equals, hashCode, and toString methods in the entity classes due to lack of null-safety.
  • A critical typo in a test configuration property.
  • Use of a shaded dependency in tests, which is not a best practice.

I've provided suggestions to fix these issues to improve code quality, correctness, and maintainability.

*/
@Import(TestcontainersConfiguration.class)
@Testcontainers
@SpringBootTest(webEnvironment = RANDOM_PORT, properties = "spring.jpa.hibernate.Ïddl-auto=create-drop")

Choose a reason for hiding this comment

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

critical

There is a typo in the properties attribute. Ïddl-auto should be ddl-auto. The character Ï is a non-standard ASCII character that was likely inserted by mistake. This will cause the property to be ignored, which could lead to unexpected test behavior or failures.

Suggested change
@SpringBootTest(webEnvironment = RANDOM_PORT, properties = "spring.jpa.hibernate.Ïddl-auto=create-drop")
@SpringBootTest(webEnvironment = RANDOM_PORT, properties = "spring.jpa.hibernate.ddl-auto=create-drop")

Comment on lines 39 to 46
public final boolean equals(Object o) {
return o instanceof Id another && this.id.equals(another.id);
}

@Override
public int hashCode() {
return id.hashCode();
}

Choose a reason for hiding this comment

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

high

The equals and hashCode methods in the Id class can throw a NullPointerException if this.id is null. This can happen if an Author entity is new and has not yet been persisted. It's safer to use java.util.Objects to handle potential nulls.

Suggested change
public final boolean equals(Object o) {
return o instanceof Id another && this.id.equals(another.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public final boolean equals(Object o) {
return o instanceof Id another && java.util.Objects.equals(this.id, another.id);
}
@Override
public int hashCode() {
return java.util.Objects.hashCode(id);
}

Comment on lines +74 to +76
public String toString() {
return String.format("%d%d%d%d%d", prefix, group, registrant, publication, check);
}

Choose a reason for hiding this comment

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

high

The toString() method is susceptible to a NullPointerException because the %d format specifier in String.format does not handle null Integer values. This can happen if an Isbn object is created via the default constructor and its fields are not initialized. Using the %s specifier is a safer alternative as it handles nulls gracefully.

Suggested change
public String toString() {
return String.format("%d%d%d%d%d", prefix, group, registrant, publication, check);
}
@Override
public String toString() {
return String.format("%s%s%s%s%s", prefix, group, registrant, publication, check);
}

import org.springframework.context.annotation.Import;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.shaded.org.apache.commons.lang3.math.NumberUtils;

Choose a reason for hiding this comment

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

medium

Using a shaded dependency from Testcontainers (org.testcontainers.shaded.org.apache.commons.lang3.math.NumberUtils) is not recommended. Relying on shaded dependencies is risky as they might be changed or removed in future versions of Testcontainers without notice. It's better practice to declare a direct dependency on Apache Commons Lang3.

Suggested change
import org.testcontainers.shaded.org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.math.NumberUtils;

Copy link
Contributor

Job Summary for Gradle

Gradle Build :: gradle-build
Gradle Root Project Requested Tasks Gradle Version Build Outcome Build Scan®
spring-boot-tutorials build jacocoTestReport sonar 8.14.3 Build Scan published

Copy link
Contributor

Job Summary for Gradle

Gradle Build :: gradle-build
Gradle Root Project Requested Tasks Gradle Version Build Outcome Build Scan®
spring-boot-tutorials build jacocoTestReport sonar 8.14.3 Build Scan published

Copy link
Contributor

Job Summary for Gradle

Gradle Build :: gradle-build
Gradle Root Project Requested Tasks Gradle Version Build Outcome Build Scan®
spring-boot-tutorials build jacocoTestReport sonar 8.14.3 Build Scan published

Copy link

@rashidi rashidi merged commit b4f8943 into master Jul 13, 2025
8 checks passed
@rashidi rashidi deleted the data-rest/composite-key branch July 13, 2025 11:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant