Skip to content

fix: eliminate ByteBuddy UnsupportedFeatureError in GraalVM native image via proxy-free entity contracts and specialized eager queries#108

Merged
vitorhugo-java merged 2 commits intomasterfrom
copilot/refactor-hibernate-compatibility
Apr 16, 2026
Merged

fix: eliminate ByteBuddy UnsupportedFeatureError in GraalVM native image via proxy-free entity contracts and specialized eager queries#108
vitorhugo-java merged 2 commits intomasterfrom
copilot/refactor-hibernate-compatibility

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 16, 2026

  • Analyze entity models, repositories, and service flows
  • Fix MediaModel.equals/hashCode — remove HibernateProxy (root cause of ByteBuddy UnsupportedFeatureError)
  • Fix ExternalReferenceModel.equals/hashCode — remove HibernateProxy
  • Add findByIdWithExternalReferences specialized query to MediaRepository for the update/detail flow
  • Update MediaServiceImpl.findByIdEager to use the new eager query (loads externalReference at query time, not lazily)
  • Fix MediaRepository Javadoc — accurately state which collections are handled by MediaLazyLoader vs @BatchMapping
  • Clean up MediaServiceImpl.findByIdEager — remove redundant cast, use Optional directly, drop stale @SuppressWarnings (Qodana/review)
  • Add unit tests for findByIdEager — verify specialized query is used and LazyLoader is called

…ed eager-load query for GraalVM native image compatibility

- MediaModel: replace HibernateProxy-based equals/hashCode with standard
  ID-based implementation (removes ByteBuddy dependency at runtime)
- ExternalReferenceModel: same fix
- MediaRepository: add findByIdWithExternalReferences() — JOIN FETCH query
  that eagerly loads only the externalReference collection; prevents lazy-load
  after session close in the update/detail flow without Cartesian products
- MediaServiceImpl.findByIdEager: use findByIdWithExternalReferences() instead
  of plain findById() so external references are pre-loaded before updateAllInformation
  is called; MediaLazyLoader still handles alternativeTitles/genre/season separately

Agent-Logs-Url: https://github.com/EspacoGeek-Teams/SpringAPI_EspacoGeek/sessions/cb902dbd-4ccb-454f-9fe5-3b5d40352431

Co-authored-by: vitorhugo-java <65777252+vitorhugo-java@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 16, 2026

Qodana for JVM

5 new problems were found

Inspection name Severity Problems
Constant values 🔶 Warning 3
Unnecessary 'null' check before method call 🔶 Warning 1
Unused assignment 🔶 Warning 1
View the detailed Qodana report

To be able to view the detailed Qodana report, you can either:

To get *.log files or any other Qodana artifacts, run the action with upload-result option set to true,
so that the action will upload the files as the job artifacts:

      - name: 'Qodana Scan'
        uses: JetBrains/qodana-action@v2025.3.2
        with:
          upload-result: true
Contact Qodana team

Contact us at qodana-support@jetbrains.com

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +126 to +129
* {@code externalReference} via a single JOIN FETCH avoids loading all six lazy collections
* and prevents accidental Cartesian products. The remaining collections
* ({@code alternativeTitles}, {@code genre}, {@code season}) are loaded on demand by
* {@link com.espacogeek.geek.utils.MediaLazyLoader} when needed.
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

The new Javadoc is a bit misleading: it says fetching only externalReference avoids loading “all six lazy collections”, but then implies the “remaining collections” are only alternativeTitles, genre, season loaded by MediaLazyLoader. MediaModel also has lazy company and people collections, and MediaLazyLoader does not initialize those. Please adjust the wording to clearly state which collections are initialized by MediaLazyLoader vs. left for other resolvers (e.g., GraphQL @BatchMapping) so future readers don’t assume everything else is covered.

Suggested change
* {@code externalReference} via a single JOIN FETCH avoids loading all six lazy collections
* and prevents accidental Cartesian products. The remaining collections
* ({@code alternativeTitles}, {@code genre}, {@code season}) are loaded on demand by
* {@link com.espacogeek.geek.utils.MediaLazyLoader} when needed.
* {@code externalReference} via a single JOIN FETCH avoids eagerly loading the other lazy
* collections and helps prevent accidental Cartesian products. This query initializes only
* {@code externalReference}; {@code alternativeTitles}, {@code genre}, and {@code season}
* may still be initialized on demand by
* {@link com.espacogeek.geek.utils.MediaLazyLoader}, while {@code company} and
* {@code people} are left to other resolvers such as GraphQL {@code @BatchMapping}.

Copilot uses AI. Check for mistakes.
Comment on lines +201 to +205
public Optional<MediaModel> findByIdEager(Integer id) {
MediaModel media = (MediaModel) mediaRepository.findById(id).orElse(null);
// Use the specialized query that eagerly fetches externalReference in a single JOIN FETCH.
// This avoids a lazy-load of externalReference later in the update flow, where the
// Hibernate session may no longer be active (e.g. virtual-thread context switches).
MediaModel media = (MediaModel) mediaRepository.findByIdWithExternalReferences(id).orElse(null);
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

findByIdWithExternalReferences already returns Optional<MediaModel>, so the explicit cast to MediaModel and the orElse(null) + null check are redundant. Consider using the Optional directly (e.g., early-return on empty, then operate on the value) and dropping method-level warning suppressions that are no longer needed, to avoid masking real warnings later.

Copilot uses AI. Check for mistakes.
// Use the specialized query that eagerly fetches externalReference in a single JOIN FETCH.
// This avoids a lazy-load of externalReference later in the update flow, where the
// Hibernate session may no longer be active (e.g. virtual-thread context switches).
MediaModel media = (MediaModel) mediaRepository.findByIdWithExternalReferences(id).orElse(null);
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

findByIdEager now relies on the new MediaRepository#findByIdWithExternalReferences query and the expectation that MediaLazyLoader.initializeCollections is invoked afterward. There are existing unit/integration tests for MediaServiceImpl, but none currently cover findByIdEager; adding a test that verifies the repository method used and that the lazy-loader is called would help prevent regressions in this eager-loading behavior.

Copilot uses AI. Check for mistakes.
@vitorhugo-java
Copy link
Copy Markdown
Owner

@copilot apply changes based on the comments in this thread and fix the issues of Qodana for JVM

…iew feedback

- MediaRepository: corrected Javadoc for findByIdWithExternalReferences;
  now accurately names company/people as @BatchMapping-resolved (not via
  MediaLazyLoader) per reviewer suggestion
- MediaServiceImpl.findByIdEager: removed redundant (MediaModel) cast and
  orElse(null)+null-check anti-pattern; use Optional.isEmpty()/get() directly;
  dropped stale method-level @SuppressWarnings that masked nothing meaningful
- MediaServiceImplTest: add findByIdEager_WhenMediaExists — verifies the
  specialized JOIN FETCH query is used (not findById) and that MediaLazyLoader
  is called; add findByIdEager_WhenMediaNotFound — verifies empty Optional is
  returned and neither findById nor initializeCollections are called

Agent-Logs-Url: https://github.com/EspacoGeek-Teams/SpringAPI_EspacoGeek/sessions/ff0f150c-3e9c-4ad7-a8f2-19b955101e4f

Co-authored-by: vitorhugo-java <65777252+vitorhugo-java@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 16, 2026

@copilot apply changes based on the comments in this thread and fix the issues of Qodana for JVM

Applied in commit b2e3fea:

  • MediaRepository Javadoc — updated to accurately state that externalReference, alternativeTitles, genre, and season are the collections addressed, while company and people are left to GraphQL @BatchMapping resolvers
  • findByIdEager cleanup — removed the redundant (MediaModel) cast (the method already returns Optional<MediaModel>), replaced orElse(null) + null-check with Optional.isEmpty() / .get(), and dropped the stale method-level @SuppressWarnings
  • Unit tests — added findByIdEager_WhenMediaExists (verifies findByIdWithExternalReferences is called instead of findById, and initializeCollections is invoked) and findByIdEager_WhenMediaNotFound (verifies empty Optional is returned without touching the lazy loader)

Copilot AI requested a review from vitorhugo-java April 16, 2026 14:29
@vitorhugo-java vitorhugo-java merged commit b3600fb into master Apr 16, 2026
3 checks passed
@github-actions github-actions Bot added the tests label Apr 16, 2026
@vitorhugo-java vitorhugo-java deleted the copilot/refactor-hibernate-compatibility branch April 16, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants