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

CRJVM 205 : Forcer l'utilisation du FetchType LAZY sur les collections dans les Entity JPA #125

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Some are applicable for different technologies.
| | Use official social media sharing buttons | These JavaScript plugins are very resource-intensive: to work, they require a large number of requests and download heavy files. It is better to prefer direct links. | [cnumr best practices (3rd edition) BP_019](https://github.com/cnumr/best-practices/blob/main/chapters/BP_019_fr.md) | 🚫 | 🚫 | 🚀 | 🚫 | 🚫 |
| | Non-grouped similar CSS declarations | When multiple Document Object Model (DOM) elements have common CSS properties, declare them together in the same style sheet. This method reduces the weight of CSS. |[cnumr best practices (3rd edition) BP_025](https://github.com/cnumr/best-practices/blob/main/chapters/BP_025_fr.md) | 🚫 | 🚫 | 🚧 | 🚫 | 🚫 |
| | CSS shorthand notations not used | Reduces the weight of the style sheet. | [cnumr best practices (3rd edition) BP_026](https://github.com/cnumr/best-practices/blob/main/chapters/BP_026_fr.md) | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 |
| | CSS print not included | This style sheet reduces the number of pages printed. | [cnumr best practices (3rd edition) BP_027](https://github.com/cnumr/best-practices/blob/main/chapters/BP_027_fr.md) | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 |
| | CSS[INSTALL.md](INSTALL.md) print not included | This style sheet reduces the number of pages printed. | [cnumr best practices (3rd edition) BP_027](https://github.com/cnumr/best-practices/blob/main/chapters/BP_027_fr.md) | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 |
| | Non-standard fonts used | Prefer standard fonts, as they are already present on the user's computer, so they do not need to download them. This saves bandwidth, while speeding up the display of the site. | [cnumr best practices (3rd edition) BP_029](https://github.com/cnumr/best-practices/blob/main/chapters/BP_029_fr.md) | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 |
| | Non-outsourced CSS and Javascript | If you include CSS or JavaScript code in the body of the HTML file, while the HTML file is used by several pages (or even the entire site), this code must be transferred for each page requested by the user, which increases the volume of data transmitted. | [cnumr best practices (3rd edition) BP_032](https://github.com/cnumr/best-practices/blob/main/chapters/BP_032_fr.md) | 🚫 | 🚫 | 🚀 | 🚫 | 🚫 |
| | Resize images browser-side | Do not resize images using the HEIGHT and WIDTH attributes of the HTML code. This approach requires transferring these images to their original size, wasting bandwidth and CPU cycles. | [cnumr best practices (3rd edition) BP_034](https://github.com/cnumr/best-practices/blob/main/chapters/BP_034_fr.md) | 🚫 | 🚫 | 🚧 | 🚫 | 🚫 |
Expand Down Expand Up @@ -47,3 +47,4 @@ Some are applicable for different technologies.
| EC28 | Optimize read file exceptions | | | ✅ | 🚫 | 🚫 | 🚫 | 🚫 |
| EC5 | Usage of preparedStatement instead of Statement | SQL will only commit the query once, whereas if you used only one statement, it would commit the query every time and thus induce unnecessary calculations by the CPU and therefore superfluous energy consumption. | | ✅ | 🚫 | 🚫 | 🚫 | 🚫 |
| EC27 | Usage of system.arraycopy to copy arrays | Programs spend most of the time in loops. These can be resource consuming, especially when they integrate heavy processing (IO access). Moreover, the size of the data and processing inside the loops will not allow full use of hardware mechanisms such as the cache or compiler optimization mechanisms. | | ✅ | 🚫 | 🚫 | 🚫 | 🚫 |
|CRJVM205| Use lazy fetch type instead of egger
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package fr.greencodeinitiative.java.checks;

import org.sonar.check.Priority;
import org.sonar.check.Rule;
import org.sonar.java.ast.parser.ArgumentListTreeImpl;
import org.sonar.java.model.declaration.AnnotationTreeImpl;
import org.sonar.java.model.expression.AssignmentExpressionTreeImpl;
import org.sonar.java.model.expression.MemberSelectExpressionTreeImpl;
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
import org.sonar.plugins.java.api.tree.Tree;
import org.sonar.plugins.java.api.tree.TypeTree;

import java.util.List;

import static java.util.Collections.singletonList;

@Rule(
key = "CRJVM205",
name = "Developpement",
description = AvoidFullSQLRequest.MESSAGERULE,
priority = Priority.MINOR,
tags = {"bug"})
public class FetchTypeLazyCheck extends IssuableSubscriptionVisitor {
public static final String MANY_TO_ONE = "ManyToOne";
public static final String LAZY = "LAZY";
public static final String ONE_TO_MANY = "OneToMany";
protected static final String MESSAGERULE = "Use lazy fetch type instead of egger";

@Override
public List<Tree.Kind> nodesToVisit() {
return singletonList(Tree.Kind.ANNOTATION);
}


@Override
public void visitNode(Tree tree) {
TypeTree typeTree = ((AnnotationTreeImpl) tree).annotationType();
if (MANY_TO_ONE.equals(typeTree.symbolType().name()) || ONE_TO_MANY.equals(typeTree.symbolType().name()) || "ManyToMany".equals(typeTree.symbolType().name())) {
visitAnnotations(tree);
}
}

private void visitAnnotations(final Tree tree) {
List<Tree> annotationListTree = ((AnnotationTreeImpl) tree).children();
if (!annotationListTree.isEmpty() && annotationListTree.size() > 1) {
ArgumentListTreeImpl argumentListTree = (ArgumentListTreeImpl) annotationListTree.get(2);
visitArguments(argumentListTree, tree);
}
}

private void visitArguments(final ArgumentListTreeImpl argumentListTree, final Tree tree) {
List<Tree> argumentListTreeChildren = argumentListTree.getChildren();
if (!argumentListTreeChildren.isEmpty() && argumentListTreeChildren.size() > 1) {
AssignmentExpressionTreeImpl assignmentExpressionTree = (AssignmentExpressionTreeImpl) argumentListTreeChildren.get(1);
visitAssignements(assignmentExpressionTree, tree);
}
}

private void visitAssignements(final AssignmentExpressionTreeImpl assignmentExpressionTree, final Tree tree) {
List<Tree> assignmentExpressionTreeChildren = assignmentExpressionTree.getChildren();
if (!assignmentExpressionTreeChildren.isEmpty() && assignmentExpressionTreeChildren.size() > 1) {
MemberSelectExpressionTreeImpl memberSelectExpressionTree = (MemberSelectExpressionTreeImpl) assignmentExpressionTreeChildren.get(2);
checkFetchTypeManyToOne(tree, memberSelectExpressionTree);
}
}

private void checkFetchTypeManyToOne(final Tree tree, final MemberSelectExpressionTreeImpl memberSelectExpressionTree) {
if (!LAZY.equals(memberSelectExpressionTree.identifier()
.name())) {
reportIssue(tree, MESSAGERULE);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<p>Use lazy fetch type instead of egger.</p>
<h2>Noncompliant Code Example</h2>
<pre>
class FetchTypeLazyCheck {

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="USER_ID")
private UserLazy user;

}
</pre>
<h2>Compliant Solution</h2>
<pre>
class FetchTypeLazyCheck {

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="USER_ID")
private UserLazy user;

}

OR

class FetchTypeLazyCheck {

@ManyToOne
@JoinColumn(name="USER_ID")
private UserLazy user;

}

</pre>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"title": "Use lazy fetch type instead of egger",
"type": "CODE_SMELL",
"status": "ready",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "20min"
},
"tags": [
"eco-design",
"performance",
"orm",
"jpa",
"ecocode"
],
"defaultSeverity": "Minor"
}
19 changes: 19 additions & 0 deletions java-plugin/src/test/files/FetchTypeLazyCheckBad.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package fr.greencodeinitiative.java.checks;

import java.util.regex.Pattern;
@Entity
@Table (name = "ECO_CODE")
class FetchTypeLazyCheck {
FetchTypeLazyCheck(FetchTypeLazyCheck mc) {
}

@Id
@GeneratedValue
@Column(name="ORDER_ID")
private Long orderId;

@ManyToOne(fetch = FetchType.EAGER) // Noncompliant {{Use lazy fetch type instead of egger}}
@JoinColumn(name="USER_ID")
private UserLazy user;

}
19 changes: 19 additions & 0 deletions java-plugin/src/test/files/FetchTypeLazyCheckGood.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package fr.greencodeinitiative.java.checks;

import java.util.regex.Pattern;
@Entity
@Table (name = "ECO_CODE")
class FetchTypeLazyCheck {
FetchTypeLazyCheck(FetchTypeLazyCheck mc) {
}

@Id
@GeneratedValue
@Column(name="ORDER_ID")
private Long orderId;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="USER_ID")
private UserLazy user;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package fr.greencodeinitiative.java.checks;

import org.junit.jupiter.api.Test;
import org.sonar.java.checks.verifier.CheckVerifier;

class FetchTypeLazyCheckTest {

@Test
void testNoIssues() {
CheckVerifier.newVerifier()
.onFile("src/test/files/FetchTypeLazyCheckGood.java")
.withCheck(new FetchTypeLazyCheck())
.verifyNoIssues();
}


@Test
void testIssues() {
CheckVerifier.newVerifier()
.onFile("src/test/files/FetchTypeLazyCheckBad.java")
.withCheck(new FetchTypeLazyCheck())
.verifyIssues();
}

}