diff --git a/RULES.md b/RULES.md index d3add4cb8..3d20d562a 100644 --- a/RULES.md +++ b/RULES.md @@ -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) | 🚫 | 🚫 | 🚧 | 🚫 | 🚫 | @@ -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 \ No newline at end of file diff --git a/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/FetchTypeLazyCheck.java b/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/FetchTypeLazyCheck.java new file mode 100644 index 000000000..2a9131a84 --- /dev/null +++ b/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/FetchTypeLazyCheck.java @@ -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 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 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 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 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); + } + } +} diff --git a/java-plugin/src/main/resources/fr/greencodeinitiative/l10n/java/rules/java/CRJVM205.html b/java-plugin/src/main/resources/fr/greencodeinitiative/l10n/java/rules/java/CRJVM205.html new file mode 100644 index 000000000..a9bd32368 --- /dev/null +++ b/java-plugin/src/main/resources/fr/greencodeinitiative/l10n/java/rules/java/CRJVM205.html @@ -0,0 +1,32 @@ +

Use lazy fetch type instead of egger.

+

Noncompliant Code Example

+
+  class FetchTypeLazyCheck {
+
+    @ManyToOne(fetch = FetchType.EAGER)
+    @JoinColumn(name="USER_ID")
+    private UserLazy user;
+
+   }
+
+

Compliant Solution

+
+  class FetchTypeLazyCheck {
+
+        @ManyToOne(fetch = FetchType.LAZY)
+        @JoinColumn(name="USER_ID")
+        private UserLazy user;
+
+   }
+
+    OR
+
+    class FetchTypeLazyCheck {
+
+        @ManyToOne
+        @JoinColumn(name="USER_ID")
+        private UserLazy user;
+
+   }
+
+
diff --git a/java-plugin/src/main/resources/fr/greencodeinitiative/l10n/java/rules/java/CRJVM205.json b/java-plugin/src/main/resources/fr/greencodeinitiative/l10n/java/rules/java/CRJVM205.json new file mode 100644 index 000000000..67910bbe4 --- /dev/null +++ b/java-plugin/src/main/resources/fr/greencodeinitiative/l10n/java/rules/java/CRJVM205.json @@ -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" +} diff --git a/java-plugin/src/test/files/FetchTypeLazyCheckBad.java b/java-plugin/src/test/files/FetchTypeLazyCheckBad.java new file mode 100644 index 000000000..b64cc7662 --- /dev/null +++ b/java-plugin/src/test/files/FetchTypeLazyCheckBad.java @@ -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; + +} diff --git a/java-plugin/src/test/files/FetchTypeLazyCheckGood.java b/java-plugin/src/test/files/FetchTypeLazyCheckGood.java new file mode 100644 index 000000000..00c31c6b7 --- /dev/null +++ b/java-plugin/src/test/files/FetchTypeLazyCheckGood.java @@ -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; + +} diff --git a/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/FetchTypeLazyCheckTest.java b/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/FetchTypeLazyCheckTest.java new file mode 100644 index 000000000..ce4e32e5a --- /dev/null +++ b/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/FetchTypeLazyCheckTest.java @@ -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(); + } + +}