Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
5 changes: 2 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- [#407](https://github.com/green-code-initiative/creedengo-rules-specifications/pull/407): GCI115 - Python - Detect a for loop and suggest a list comprehension
- [#481](https://github.com/green-code-initiative/creedengo-rules-specifications/pull/481) Add rule GCI114 for Python: Avoid range(len()) pattern, prefer direct iteration or enumerate()
- Add search words in rules file

### Added
- [#407](https://github.com/green-code-initiative/creedengo-rules-specifications/pull/407): GCI115 - Python - Detect a for loop and suggest a list comprehension
- [#487](https://github.com/green-code-initiative/creedengo-rules-specifications/pull/487) Add complete analysis for FetchType issue for Java (sonarqube built-in rule S6904)

### Changed

Expand Down
32 changes: 16 additions & 16 deletions RULES.md

Large diffs are not rendered by default.

106 changes: 106 additions & 0 deletions src/main/rules/S6904/java/S6904.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
:!sectids:

== Why is this rule isn't a "GCIxxx" rule ?

Because the rule already exists as built-in rule inside SonarQube with number S6904.
Some works were done by different people.
To not loose this work, we created this documentation to keep it.

== Why is this an issue?

When a JPA collection association is mapped with `FetchType.EAGER`, the persistence provider loads
the whole associated collection every time the owning entity is read, even when the application
never accesses it.

On a collection, this is not a marginal cost: a single entity read can pull an arbitrary number of
additional rows from the database. This means more CPU cycles spent by the database engine, more
data transferred over the network, and more heap allocated by the application — all for objects
that may never be used. Less data loaded into memory means less energy consumed, both on the
database server and on the application server.

`FetchType.LAZY` defers the load until the collection is actually accessed, which lets the
application pay the cost only when it needs the data.

Note that `LAZY` is already the default for `@OneToMany` and `@ManyToMany`: this rule only reports
associations where `EAGER` has been set explicitly.

== Examples

=== Noncompliant

[source,java,data-diff-id="1",data-diff-type="noncompliant"]
----
@Entity
@Table(name = "purchase_order")
public class Order {

@OneToMany(mappedBy = "order", fetch = FetchType.EAGER) // Noncompliant
private Set<OrderItem> items = new HashSet<>();

}
----

[source,java,data-diff-id="2",data-diff-type="noncompliant"]
----
@Entity
@Table(name = "purchase_order")
public class Order {

@ManyToMany(fetch = FetchType.EAGER) // Noncompliant
private Set<Tag> tags = new HashSet<>();

}
----

=== Compliant

[source,java,data-diff-id="3",data-diff-type="compliant"]
----
@Entity
@Table(name = "purchase_order")
public class Order {

@OneToMany(mappedBy = "order", fetch = FetchType.LAZY)
private Set<OrderItem> items = new HashSet<>();

}
----

[source,java,data-diff-id="4",data-diff-type="compliant"]
----
@Entity
@Table(name = "purchase_order")
public class Order {

@ManyToMany // Default fetch type for @ManyToMany is already LAZY
private Set<Tag> tags = new HashSet<>();

}
----

== Exceptions to this rule

This rule only applies to collection associations (`@OneToMany`, `@ManyToMany`).

Single-valued associations (`@ManyToOne`, `@OneToOne`) default to `FetchType.EAGER` in JPA, but
their cost profile is different: they load one additional row, not an arbitrary number. Their real
impact appears when they are traversed in a loop, which is the N+1 selects problem — a separate
concern.

No issue is raised when the `fetch` attribute is omitted on a collection association, since
`FetchType.LAZY` is already the JPA default in that case.

== Resources

=== Documentation

- [Jakarta Persistence Specification](https://jakarta.ee/specifications/persistence/) - Default fetch types for association mappings
- [Hibernate User Guide](https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#fetching) - Fetching strategies

=== Articles & blog posts

- [Eager fetching is a code smell](https://vladmihalcea.com/eager-fetching-is-a-code-smell/) - Vlad Mihalcea

=== Local measeures

check complete analysis proving that this rule is relevant, here :
Loading