diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1ce62a8..537ca76 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
+- Add new rule EC1245 - Make non reassigned variables constants
+- Add new rule EC205 - Force Lazy fetch types for JPA associations
+- Add new rule EC1245 - Avoid energy consuming methods
### Changed
diff --git a/pom.xml b/pom.xml
index fa0c7e9..44e0519 100644
--- a/pom.xml
+++ b/pom.xml
@@ -67,7 +67,7 @@
1.7
- 1.5.1
+ 1.5.7-SNAPSHOT
diff --git a/src/main/java/fr/greencodeinitiative/java/JavaCheckRegistrar.java b/src/main/java/fr/greencodeinitiative/java/JavaCheckRegistrar.java
index f4ef343..8b3a140 100644
--- a/src/main/java/fr/greencodeinitiative/java/JavaCheckRegistrar.java
+++ b/src/main/java/fr/greencodeinitiative/java/JavaCheckRegistrar.java
@@ -17,28 +17,14 @@
*/
package fr.greencodeinitiative.java;
-import java.util.Collections;
-import java.util.List;
-
-import fr.greencodeinitiative.java.checks.ArrayCopyCheck;
-import fr.greencodeinitiative.java.checks.AvoidFullSQLRequest;
-import fr.greencodeinitiative.java.checks.AvoidGettingSizeCollectionInLoop;
-import fr.greencodeinitiative.java.checks.AvoidMultipleIfElseStatement;
-import fr.greencodeinitiative.java.checks.AvoidRegexPatternNotStatic;
-import fr.greencodeinitiative.java.checks.AvoidSQLRequestInLoop;
-import fr.greencodeinitiative.java.checks.AvoidSetConstantInBatchUpdate;
-import fr.greencodeinitiative.java.checks.AvoidSpringRepositoryCallInLoopOrStreamCheck;
-import fr.greencodeinitiative.java.checks.AvoidStatementForDMLQueries;
-import fr.greencodeinitiative.java.checks.AvoidUsageOfStaticCollections;
-import fr.greencodeinitiative.java.checks.FreeResourcesOfAutoCloseableInterface;
-import fr.greencodeinitiative.java.checks.IncrementCheck;
-import fr.greencodeinitiative.java.checks.InitializeBufferWithAppropriateSize;
-import fr.greencodeinitiative.java.checks.NoFunctionCallWhenDeclaringForLoop;
-import fr.greencodeinitiative.java.checks.OptimizeReadFileExceptions;
+import fr.greencodeinitiative.java.checks.*;
import org.sonar.plugins.java.api.CheckRegistrar;
import org.sonar.plugins.java.api.JavaCheck;
import org.sonarsource.api.sonarlint.SonarLintSide;
+import java.util.Collections;
+import java.util.List;
+
/**
* Provide the "checks" (implementations of rules) classes that are going be executed during
* source code analysis.
@@ -62,7 +48,10 @@ public class JavaCheckRegistrar implements CheckRegistrar {
InitializeBufferWithAppropriateSize.class,
AvoidSetConstantInBatchUpdate.class,
FreeResourcesOfAutoCloseableInterface.class,
- AvoidMultipleIfElseStatement.class
+ AvoidMultipleIfElseStatement.class,
+ AvoidEnergyConsumingMethods.class,
+ MakeNonReassignedVariablesConstants.class,
+ ForceLazyFetchTypeForJPA.class
);
/**
diff --git a/src/main/java/fr/greencodeinitiative/java/checks/AvoidEnergyConsumingMethods.java b/src/main/java/fr/greencodeinitiative/java/checks/AvoidEnergyConsumingMethods.java
new file mode 100644
index 0000000..d721da9
--- /dev/null
+++ b/src/main/java/fr/greencodeinitiative/java/checks/AvoidEnergyConsumingMethods.java
@@ -0,0 +1,199 @@
+/*
+ * ecoCode - Java language - Provides rules to reduce the environmental footprint of your Java programs
+ * Copyright © 2023 Green Code Initiative (https://www.ecocode.io)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package fr.greencodeinitiative.java.checks;
+
+import org.sonar.check.Rule;
+import org.sonar.plugins.java.api.InputFileScannerContext;
+import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
+import org.sonar.plugins.java.api.semantic.Symbol;
+import org.sonar.plugins.java.api.tree.BaseTreeVisitor;
+import org.sonar.plugins.java.api.tree.MethodInvocationTree;
+import org.sonar.plugins.java.api.tree.MethodTree;
+import org.sonar.plugins.java.api.tree.Tree;
+import org.sonarsource.analyzer.commons.annotations.DeprecatedRuleKey;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * This rule aims to identify and flag methods in Java code that have high energy consumption
+ * due to the use of computationally expensive operations. The goal is to encourage developers
+ * to write more energy-efficient code by limiting the use of costly operations within a single method.
+ *
+ *
+ *
+ * The rule works by assigning a "cost" to specific expensive operations commonly recognized for their
+ * high computational demands. These operations include:
+ *
+ * - Reflection operations (e.g., {@code Class.forName()}, {@code Method.invoke()})
+ * - Synchronization operations (e.g., {@code synchronized} blocks or methods)
+ * - I/O operations (e.g., {@code FileInputStream}, {@code FileOutputStream}, {@code BufferedReader}, etc.)
+ * - SQL operations (e.g., {@code Statement.execute()}, {@code ResultSet.next()})
+ * - String operations (e.g., {@code String.replaceAll()}, {@code String.split()}, etc.)
+ * - ...
+ *
+ *
+ *
+ * For each occurrence of these operations within a method, a predefined number of points is assigned.
+ * If the total points for a method exceed a certain threshold (e.g., 5 points), the method is considered
+ * to be energy-inefficient. A warning is then issued to indicate that the method may have high energy
+ * consumption and suggest the developer to refactor or optimize the method.
+ *
+ *
+ *
+ * Example:
+ *
+ * {@code
+ * public class Example {
+ * public void exampleMethod() {
+ * String data = "example";
+ * data = data.replaceAll("e", "a"); // 1 point
+ * FileInputStream fis = new FileInputStream("file.txt"); // 1 point
+ * // Other operations
+ * }
+ * }
+ * }
+ *
+ *
+ * In the above example, the `exampleMethod` uses `String.replaceAll()` and `FileInputStream`,
+ * each contributing 1 point to the total score. If additional expensive operations are added
+ * and the total score exceeds 5 points, the rule will flag this method.
+ *
+ *
+ *
+ * This rule helps developers identify potential performance bottlenecks and encourages
+ * the adoption of more efficient coding practices to reduce the energy footprint of their applications.
+ *
+ * @author Massil TAGUEMOUT - CGI FRANCE
+ */
+@Rule(key = "EC1245")
+@DeprecatedRuleKey(repositoryKey = "greencodeinitiative-java", ruleKey = "EC1245")
+public class AvoidEnergyConsumingMethods extends IssuableSubscriptionVisitor {
+
+ private static final int ENERGY_THRESHOLD = 5;
+ private static final Map COSTLY_METHODS = new HashMap<>();
+
+ static {
+ // Reference costly methods in the map and their points
+ // Reflection methods
+ COSTLY_METHODS.put("java.lang.Class.forName", 1);
+ COSTLY_METHODS.put("java.lang.reflect.Method.invoke", 1);
+ COSTLY_METHODS.put("java.lang.reflect.Field.get", 1);
+ COSTLY_METHODS.put("java.lang.reflect.Field.set", 1);
+ COSTLY_METHODS.put("java.lang.reflect.Constructor.newInstance", 1);
+ COSTLY_METHODS.put("java.lang.Class.getMethods", 1);
+ COSTLY_METHODS.put("java.lang.Class.getDeclaredMethods", 1);
+ COSTLY_METHODS.put("java.lang.Class.getFields", 1);
+ COSTLY_METHODS.put("java.lang.Class.getDeclaredFields", 1);
+ COSTLY_METHODS.put("java.lang.Class.getConstructors", 1);
+ COSTLY_METHODS.put("java.lang.Class.getDeclaredConstructors", 1);
+
+ // String methods
+ COSTLY_METHODS.put("java.lang.String.concat", 1);
+ COSTLY_METHODS.put("java.lang.String.substring", 1);
+ COSTLY_METHODS.put("java.lang.String.replace", 1);
+ COSTLY_METHODS.put("java.lang.String.matches", 1);
+ COSTLY_METHODS.put("java.lang.String.split", 1);
+
+ // Collections
+ COSTLY_METHODS.put("java.util.Vector.add", 1);
+ COSTLY_METHODS.put("java.util.Vector.get", 1);
+ COSTLY_METHODS.put("java.util.Vector.remove", 1);
+ COSTLY_METHODS.put("java.util.Hashtable.put", 1);
+ COSTLY_METHODS.put("java.util.Hashtable.get", 1);
+ COSTLY_METHODS.put("java.util.Hashtable.remove", 1);
+ COSTLY_METHODS.put("java.util.Collections.synchronizedList", 1);
+ COSTLY_METHODS.put("java.util.Collections.synchronizedMap", 1);
+ COSTLY_METHODS.put("java.util.Collections.synchronizedSet", 1);
+ COSTLY_METHODS.put("java.util.Collections.synchronizedSortedMap", 1);
+ COSTLY_METHODS.put("java.util.Collections.synchronizedSortedSet", 1);
+
+ // File I/O
+ COSTLY_METHODS.put("java.io.FileInputStream.read", 1);
+ COSTLY_METHODS.put("java.io.FileOutputStream.write", 1);
+ COSTLY_METHODS.put("java.io.FileReader.read", 1);
+ COSTLY_METHODS.put("java.io.FileWriter.write", 1);
+ COSTLY_METHODS.put("java.io.RandomAccessFile.read", 1);
+ COSTLY_METHODS.put("java.io.RandomAccessFile.write", 1);
+ COSTLY_METHODS.put("java.nio.file.Files.readAllBytes", 1);
+ COSTLY_METHODS.put("java.nio.file.Files.write", 1);
+
+ // Network I/O
+ COSTLY_METHODS.put("java.net.Socket.getInputStream", 1);
+ COSTLY_METHODS.put("java.net.Socket.getOutputStream", 1);
+ COSTLY_METHODS.put("java.net.ServerSocket.accept", 1);
+ COSTLY_METHODS.put("java.net.HttpURLConnection.connect", 1);
+ COSTLY_METHODS.put("java.net.HttpURLConnection.getInputStream", 1);
+ COSTLY_METHODS.put("java.net.HttpURLConnection.getOutputStream", 1);
+
+ // JNI
+ COSTLY_METHODS.put("java.lang.System.loadLibrary", 1);
+ }
+
+ @Override
+ public List nodesToVisit() {
+ return List.of(Tree.Kind.METHOD);
+ }
+
+ @Override
+ public void visitNode(Tree tree) {
+ if (tree.is(Tree.Kind.METHOD)) {
+ MethodTree methodTree = (MethodTree) tree;
+ int score = calculateMethodEnergyScore(methodTree);
+
+ if (score > ENERGY_THRESHOLD) {
+ reportIssue(methodTree.simpleName(),
+ "This method is considered energy-consuming with a score of " + score
+ + " (maximum score of " + ENERGY_THRESHOLD + " recommended)");
+ }
+ }
+ }
+
+ private int calculateMethodEnergyScore(MethodTree methodTree) {
+ final AvoidEnergyConsumingMethodsVisitor visitor = new AvoidEnergyConsumingMethodsVisitor();
+ methodTree.accept(visitor);
+ return visitor.getScore();
+ }
+
+ @Override
+ public boolean scanWithoutParsing(InputFileScannerContext inputFileScannerContext) {
+ return super.scanWithoutParsing(inputFileScannerContext);
+ }
+
+
+ private static class AvoidEnergyConsumingMethodsVisitor extends BaseTreeVisitor {
+
+ private int score = 0;
+
+ @Override
+ public void visitMethodInvocation(MethodInvocationTree methodInvocationTree) {
+ Symbol symbol = methodInvocationTree.methodSymbol();
+ String fullyQualifiedName = symbol.owner().type().fullyQualifiedName() + "." + symbol.name();
+
+ score += COSTLY_METHODS.getOrDefault(fullyQualifiedName, 0);
+ super.visitMethodInvocation(methodInvocationTree);
+ }
+
+ public int getScore() {
+ return score;
+ }
+
+ }
+}
diff --git a/src/main/java/fr/greencodeinitiative/java/checks/ForceLazyFetchTypeForJPA.java b/src/main/java/fr/greencodeinitiative/java/checks/ForceLazyFetchTypeForJPA.java
new file mode 100644
index 0000000..29534f1
--- /dev/null
+++ b/src/main/java/fr/greencodeinitiative/java/checks/ForceLazyFetchTypeForJPA.java
@@ -0,0 +1,145 @@
+/*
+ * ecoCode - Java language - Provides rules to reduce the environmental footprint of your Java programs
+ * Copyright © 2023 Green Code Initiative (https://www.ecocode.io)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package fr.greencodeinitiative.java.checks;
+
+import org.sonar.check.Rule;
+import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
+import org.sonar.plugins.java.api.tree.*;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+
+/**
+ * This rule enforces the use of `FetchType.LAZY` for JPA associations to minimize energy consumption
+ * and improve application performance. The rule targets the following JPA annotations:
+ *
+ * - {@code @OneToMany}
+ * - {@code @ManyToMany}
+ * - {@code @OneToOne}
+ * - {@code @ManyToOne}
+ *
+ *
+ * JPA provides two types of fetch strategies for associations: `FetchType.EAGER` and `FetchType.LAZY`.
+ * - `FetchType.EAGER` loads the related entities immediately, which can result in significant performance
+ * overhead and increased energy consumption, especially when loading large collections or deeply nested
+ * entity graphs.
+ * - `FetchType.LAZY` defers the loading of the related entities until they are accessed, reducing the initial
+ * load time, memory usage, and energy consumption.
+ *
+ *
+ *
+ * This rule scans for the above-mentioned JPA annotations and checks if the `fetch` attribute is set to
+ * `FetchType.LAZY`. If the `fetch` attribute is either not defined or not set to `FetchType.LAZY`, the rule
+ * issues a warning.
+ *
+ *
+ *
+ * Example:
+ *
+ * {@code
+ * @Entity
+ * public class Order {
+ * @OneToMany(fetch = FetchType.LAZY) // Correct usage
+ * private List orderItems;
+ *
+ * @ManyToOne // Noncompliant, should specify fetch = FetchType.LAZY
+ * private Customer customer;
+ * }
+ * }
+ *
+ *
+ * Benefits of enforcing `FetchType.LAZY`:
+ *
+ * - Reduces initial data load, decreasing memory usage and startup time.
+ * - Prevents unnecessary data retrieval, lowering CPU and IO usage.
+ * - Improves overall application performance and responsiveness.
+ * - Minimizes energy consumption by avoiding the overhead of loading large amounts of data eagerly.
+ *
+ *
+ * By ensuring that JPA associations use `FetchType.LAZY`, developers can create more efficient and
+ * scalable applications that are better suited for high-performance environments with lower energy footprints.
+ *
+ * @author Massil TAGUEMOUT - CGI FRANCE
+ */
+@Rule(key = "EC205")
+public class ForceLazyFetchTypeForJPA extends IssuableSubscriptionVisitor {
+
+ @Override
+ public List nodesToVisit() {
+ return List.of(Tree.Kind.CLASS);
+ }
+
+ @Override
+ public void visitNode(Tree tree) {
+ ClassTree classTree = (ClassTree) tree;
+ for (Tree member : classTree.members()) {
+ if (member.is(Tree.Kind.VARIABLE)) {
+ VariableTree variableTree = (VariableTree) member;
+ checkFetchTypeLazy(variableTree);
+ }
+ }
+ }
+
+ private void checkFetchTypeLazy(VariableTree variableTree) {
+ List annotations = variableTree.modifiers().annotations();
+ for (AnnotationTree annotation : annotations) {
+ String annotationName = annotation.annotationType().toString();
+ if (isJpaAssociationAnnotation(annotationName)) {
+ checkLazyFetchType(annotation, variableTree);
+ }
+ }
+ }
+
+ private boolean isJpaAssociationAnnotation(String annotationName) {
+ return annotationName.equals("OneToMany") ||
+ annotationName.equals("ManyToMany") ||
+ annotationName.equals("OneToOne") ||
+ annotationName.equals("ManyToOne");
+ }
+
+ private void checkLazyFetchType(AnnotationTree annotation, VariableTree variableTree) {
+ boolean fetchTypeDefined = false;
+ boolean fetchTypeLazy = false;
+
+ for (ExpressionTree argument : annotation.arguments()) {
+ if (argument.is(Tree.Kind.ASSIGNMENT)) {
+ AssignmentExpressionTree assignment = (AssignmentExpressionTree) argument;
+ if (assignment.variable().toString().equals("fetch")) {
+ fetchTypeDefined = true;
+ ExpressionTree expression = assignment.expression();
+ if (expression.is(Tree.Kind.MEMBER_SELECT)) {
+ MemberSelectExpressionTree memberSelect = (MemberSelectExpressionTree) expression;
+ String expressionText = "";
+ try {
+ Field expressionField = memberSelect.getClass().getDeclaredField("expression");
+ expressionField.setAccessible(true);
+ expressionText = expressionField.get(memberSelect).toString();
+ } catch (NoSuchFieldException | IllegalAccessException ignored) {}
+
+ fetchTypeLazy = memberSelect.identifier().name().equals("LAZY") && expressionText.equals("FetchType");
+ }
+ }
+ }
+ }
+
+ if (!fetchTypeDefined || !fetchTypeLazy) {
+ reportIssue(variableTree.simpleName(), "FetchType should be explicitly set to LAZY for JPA associations.");
+ }
+ }
+}
diff --git a/src/main/java/fr/greencodeinitiative/java/checks/MakeNonReassignedVariablesConstants.java b/src/main/java/fr/greencodeinitiative/java/checks/MakeNonReassignedVariablesConstants.java
new file mode 100644
index 0000000..c285090
--- /dev/null
+++ b/src/main/java/fr/greencodeinitiative/java/checks/MakeNonReassignedVariablesConstants.java
@@ -0,0 +1,120 @@
+/*
+ * ecoCode - Java language - Provides rules to reduce the environmental footprint of your Java programs
+ * Copyright © 2023 Green Code Initiative (https://www.ecocode.io)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package fr.greencodeinitiative.java.checks;
+
+import org.sonar.check.Rule;
+import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
+import org.sonar.plugins.java.api.tree.*;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+/**
+ * This rule aims to promote the use of constants in Java code by identifying local variables
+ * that are never reassigned after their initial assignment and recommending their conversion
+ * to constants using the `final` modifier. By making variables constants, developers can
+ * not only enhance code readability and maintainability but also improve the energy efficiency
+ * of their applications.
+ *
+ *
+ * The rule functions by analyzing local variable declarations within methods. If a variable is
+ * declared and assigned a value, but never reassigned afterwards, it is a candidate for being
+ * marked as `final`. This practice can help the compiler optimize the code, leading to potential
+ * energy savings during execution.
+ *
+ *
+ * Example:
+ *
+ * {@code
+ * public class Example {
+ * public void exampleMethod() {
+ * int x = 10;
+ * String y = "example"; // Noncompliant, should be final
+ * x = 20; // This reassignment means x should not be final
+ * }
+ * }
+ * }
+ *
+ *
+ * In the above example, the variable `y` is never reassigned after its initial assignment,
+ * so it should be declared as `final`. The variable `x`, on the other hand, is reassigned,
+ * so it should not be declared as `final`.
+ *
+ *
+ *
+ * By converting such non-reassigned variables to constants, the following benefits can be achieved:
+ *
+ * - Enhanced Readability: Declaring variables as `final` makes it clear that their value
+ * will not change after initialization, improving the readability of the code.
+ * - Improved Maintainability: Constants reduce the likelihood of accidental reassignments,
+ * making the code easier to maintain and less prone to bugs.
+ * - Optimized Performance: The compiler and JIT (Just-In-Time) compiler can apply more
+ * aggressive optimizations on `final` variables, potentially leading to more efficient bytecode
+ * and better runtime performance.
+ * - Energy Efficiency: Optimized code typically executes faster and consumes less energy,
+ * contributing to the overall energy efficiency of the application.
+ *
+ *
+ * This rule helps developers write more efficient, robust, and maintainable code by encouraging
+ * the use of constants where appropriate.
+ *
+ * @author Massil TAGUEMOUT - CGI FRANCE
+ */
+@Rule(key = "EC82")
+public class MakeNonReassignedVariablesConstants extends IssuableSubscriptionVisitor {
+
+ @Override
+ public List nodesToVisit() {
+ return List.of(Tree.Kind.METHOD, Tree.Kind.CONSTRUCTOR);
+ }
+
+ @Override
+ public void visitNode(Tree tree) {
+ MethodTree methodTree = (MethodTree) tree;
+ Set reassignedVariables = new HashSet<>();
+ Set declaredVariables = new HashSet<>();
+
+ // Collect reassigned and declared variables
+ methodTree.accept(new BaseTreeVisitor() {
+ @Override
+ public void visitVariable(VariableTree variableTree) {
+ declaredVariables.add(variableTree);
+ super.visitVariable(variableTree);
+ }
+
+ @Override
+ public void visitAssignmentExpression(AssignmentExpressionTree tree) {
+ if (tree.variable().is(Tree.Kind.IDENTIFIER)) {
+ reassignedVariables.add(((IdentifierTree) tree.variable()).name());
+ }
+ super.visitAssignmentExpression(tree);
+ }
+ });
+
+ // Check for variables that are declared but not reassigned and recommend making them final
+ for (VariableTree variableTree : declaredVariables) {
+ String variableName = variableTree.simpleName().name();
+ if (!reassignedVariables.contains(variableName) && !variableTree.symbol().isFinal()) {
+ reportIssue(variableTree.simpleName(), "Consider declaring '" + variableName + "' as a constant by using the 'final' modifier.");
+ }
+ }
+ }
+
+}
diff --git a/src/test/files/AvoidEnergyConsumingMethodsCheck.java b/src/test/files/AvoidEnergyConsumingMethodsCheck.java
new file mode 100644
index 0000000..171aa7d
--- /dev/null
+++ b/src/test/files/AvoidEnergyConsumingMethodsCheck.java
@@ -0,0 +1,271 @@
+/*
+ * ecoCode - Java language - Provides rules to reduce the environmental footprint of your Java programs
+ * Copyright © 2023 Green Code Initiative (https://www.ecocode.io)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package fr.greencodeinitiative.java.checks;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.net.*;
+import java.nio.file.*;
+import java.sql.*;
+import java.util.*;
+
+public class AvoidEnergyConsumingMethodsCheck {
+
+ // Reflection Methods Example
+ public void reflectionMethodsTest_ok() throws Exception {
+ Class> clazz = Class.forName("com.sonar.SomeClass");
+ Method method = clazz.getMethod("someMethod");
+ }
+
+ public void reflectionMethodsTest_ko() throws Exception { // Noncompliant
+ Class> clazz = Class.forName("com.sonar.SomeClass");
+ Method method = clazz.getMethod("someMethod");
+ Object instance = clazz.getDeclaredConstructor().newInstance();
+ method.invoke(instance);
+
+ Field field = clazz.getDeclaredField("someField");
+ field.setAccessible(true);
+ Object value = field.get(instance);
+ field.set(instance, value);
+ field.set(instance, value);
+ }
+
+ // String Manipulation Example
+ public void stringManipulationTest_ok() {
+ String result = "";
+ result += "example";
+ }
+
+ public void stringManipulationTest_ko() { // Noncompliant
+ String result = "";
+ for (int i = 0; i < 10; i++) {
+ result += "example";
+ }
+
+ String str = "This is a test";
+ str = str.replace("test", "sample");
+ str = str.substring(5, 10);
+ boolean matches = str.matches("\\d+");
+ String[] parts = str.split(" ");
+ String[] parts = str.split(" ");
+ String[] parts = str.split(" ");
+ }
+
+ // Synchronized Collections Example
+ public void synchronizedCollectionsTest_ok() {
+ List list = Collections.synchronizedList(new ArrayList<>());
+ list.add(1);
+
+ Map map = Collections.synchronizedMap(new HashMap<>());
+ map.put("key1", "value1");
+ }
+
+ public void synchronizedCollectionsTest_ko() { // Noncompliant
+ List list = Collections.synchronizedList(new ArrayList<>());
+ list.add(1);
+ list.add(2);
+ list.get(0);
+
+ Map map = Collections.synchronizedMap(new HashMap<>());
+ map.put("key1", "value1");
+ map.get("key1");
+ map.remove("key1");
+
+ Set set = Collections.synchronizedSet(new HashSet<>());
+ Set set = Collections.synchronizedSet(new HashSet<>());
+ Set set = Collections.synchronizedSet(new HashSet<>());
+ Set set = Collections.synchronizedSet(new HashSet<>());
+ set.add("item1");
+ set.remove("item1");
+ }
+
+ // File IO Example
+ public void fileIOTest_ok() throws IOException {
+ try (FileInputStream fis = new FileInputStream("file.txt")) {
+ fis.read();
+ }
+ }
+
+ public void fileIOTest_ko() throws IOException { // Noncompliant
+ try (FileInputStream fis = new FileInputStream("file.txt")) {
+ int data = fis.read();
+ while (data != -1) {
+ data = fis.read();
+ }
+ }
+
+ try (FileOutputStream fos = new FileOutputStream("file.txt")) {
+ fos.write("Hello, World!".getBytes());
+ fos.write("Hello, World!".getBytes());
+ fos.write("Hello, World!".getBytes());
+ }
+
+ Path path = Paths.get("file.txt");
+ Path path = Paths.get("file.txt");
+ byte[] fileBytes = Files.readAllBytes(path);
+ Files.write(path, "Hello, World!".getBytes());
+ }
+
+ // Network IO Example
+ public void networkIOTest_ok() throws IOException {
+ try (Socket socket = new Socket("localhost", 8080)) {
+ socket.getInputStream();
+ }
+ }
+
+ public void networkIOTest_ko() throws IOException { // Noncompliant
+ try (Socket socket = new Socket("localhost", 8080)) {
+ InputStream is = socket.getInputStream();
+ OutputStream os = socket.getOutputStream();
+ OutputStream os = socket.getOutputStream();
+ os.write("Hello".getBytes());
+ is.read();
+ }
+
+ try (ServerSocket serverSocket = new ServerSocket(8080)) {
+ Socket clientSocket = serverSocket.accept();
+ InputStream is = clientSocket.getInputStream();
+ OutputStream os = clientSocket.getOutputStream();
+ os.write("Hello".getBytes());
+ is.read();
+ }
+
+ URL url = new URL("http://example.com");
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.connect();
+ connection.connect();
+ InputStream is = connection.getInputStream();
+ OutputStream os = connection.getOutputStream();
+ os.write("Hello".getBytes());
+ is.read();
+ }
+
+ // JNI Example
+ public void jniTest_ok() {
+ System.loadLibrary("nativeLib");
+ }
+
+ public void jniTest_ko() { // Noncompliant
+ System.loadLibrary("nativeLib");
+ System.loadLibrary("nativeLib");
+ System.loadLibrary("nativeLib");
+ System.loadLibrary("nativeLib");
+ System.loadLibrary("nativeLib");
+ System.loadLibrary("nativeLib");
+ }
+
+ // Combined Example
+ public void combinedTest_ok() throws Exception {
+ // Reflection
+ Class> clazz = Class.forName("com.sonar.SomeClass");
+ Method method = clazz.getMethod("someMethod");
+
+ // String manipulation
+ String result = "";
+ for (int i = 0; i < 2; i++) {
+ result += "example";
+ }
+
+ // File IO
+ try (FileInputStream fis = new FileInputStream("file.txt")) {
+ fis.read();
+ }
+
+ // Network IO
+ try (Socket socket = new Socket("localhost", 8080)) {
+ socket.getInputStream();
+ }
+ }
+
+ public void combinedTest_ko() throws Exception { // Noncompliant
+ // Reflection
+ Class> clazz = Class.forName("com.sonar.SomeClass");
+ Method method = clazz.getMethod("someMethod");
+ Object instance = clazz.getDeclaredConstructor().newInstance();
+ method.invoke(instance);
+
+ // String manipulation
+ String result = "";
+ for (int i = 0; i < 10; i++) {
+ result += "example";
+ }
+
+ // File IO
+ try (FileInputStream fis = new FileInputStream("file.txt")) {
+ int data = fis.read();
+ while (data != -1) {
+ data = fis.read();
+ }
+ }
+
+ // Network IO
+ try (Socket socket = new Socket("localhost", 8080)) {
+ InputStream is = socket.getInputStream();
+ OutputStream os = socket.getOutputStream();
+ os.write("Hello".getBytes());
+ is.read();
+ }
+ }
+
+ // Combined Costly Methods Example
+ public void combinedCostlyMethodsTest_ok() {
+ // String manipulation
+ String result = "";
+ for (int i = 0; i < 2; i++) {
+ result += "example";
+ }
+
+ // Reflection
+ try {
+ Class> clazz = Class.forName("com.sonar.SomeClass");
+ Method method = clazz.getMethod("someMethod");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void combinedCostlyMethodsTest_ko() { // Noncompliant
+ // String manipulation
+ String result = "";
+ for (int i = 0; i < 10; i++) {
+ result += "example";
+ }
+
+ // Reflection
+ try {
+ Class> clazz1 = Class.forName("com.sonar.SomeClass");
+ Class> clazz = Class.forName("com.sonar.SomeClass");
+ Method method = clazz.getMethod("someMethod");
+ Object instance = clazz.getDeclaredConstructor().newInstance();
+ method.invoke(instance);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ // File IO
+ try (FileInputStream fis = new FileInputStream("file.txt")) {
+ int data = fis.read();
+ while (data != -1) {
+ data = fis.read();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/files/ForceLazyFetchTypeForJPACheck.java b/src/test/files/ForceLazyFetchTypeForJPACheck.java
new file mode 100644
index 0000000..d07a8b7
--- /dev/null
+++ b/src/test/files/ForceLazyFetchTypeForJPACheck.java
@@ -0,0 +1,67 @@
+/*
+ * ecoCode - Java language - Provides rules to reduce the environmental footprint of your Java programs
+ * Copyright © 2023 Green Code Initiative (https://www.ecocode.io)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package fr.greencodeinitiative.java.checks;
+
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.ManyToMany;
+import javax.persistence.OneToOne;
+
+@Entity
+public class JpaEntity {
+
+ @OneToMany
+ private List children; // Noncompliant
+
+ @ManyToMany
+ private Set others; // Noncompliant
+
+ @OneToOne
+ private OneEntity one; // Noncompliant
+
+ @ManyToOne
+ private ManyEntity many; // Noncompliant
+
+ @OneToMany(fetch = FetchType.EAGER)
+ private List someEntitiesEager; // Noncompliant
+
+ @ManyToMany(fetch = FetchType.EAGER)
+ private Set othersEager; // Noncompliant
+
+ @OneToOne(fetch = FetchType.EAGER)
+ private OneEntity oneEager; // Noncompliant
+
+ @ManyToOne(fetch = FetchType.EAGER)
+ private ManyEntity manyEager; // Noncompliant
+
+ @OneToMany(fetch = FetchType.LAZY)
+ private List someEntitiesLazy;
+
+ @ManyToMany(fetch = FetchType.LAZY)
+ private Set othersLazy;
+
+ @OneToOne(fetch = FetchType.LAZY)
+ private OneEntity oneLazy;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ private ManyEntity manyLazy;
+
+}
\ No newline at end of file
diff --git a/src/test/files/MakeNonReassignedVariablesConstantsCheck.java b/src/test/files/MakeNonReassignedVariablesConstantsCheck.java
new file mode 100644
index 0000000..499bd89
--- /dev/null
+++ b/src/test/files/MakeNonReassignedVariablesConstantsCheck.java
@@ -0,0 +1,50 @@
+/*
+ * ecoCode - Java language - Provides rules to reduce the environmental footprint of your Java programs
+ * Copyright © 2023 Green Code Initiative (https://www.ecocode.io)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package fr.greencodeinitiative.java.checks;
+
+public class MakeNonReassignedVariablesConstantsCheck {
+
+ public void variableReassignedTest() {
+ int y = 10;
+ final double PI = 3.14159;
+
+ y = x + 5;
+
+ System.out.println(y);
+ System.out.println(PI);
+ }
+
+ public void variableNotReassignedTest() {
+ int y = 10; // Noncompliant
+ final double PI = 3.14159;
+
+ System.out.println(y);
+ System.out.println(PI);
+ }
+
+ /*
+ public void nonReassignedVariable_ko(int x, final String name) {
+ final int y = 10;
+ final double PI = 3.14159;
+
+ System.out.println(x);
+ System.out.println(name);
+ System.out.println(y);
+ System.out.println(PI);
+ }*/
+}
\ No newline at end of file
diff --git a/src/test/java/fr/greencodeinitiative/java/checks/AvoidEnergyConsumingMethodsTest.java b/src/test/java/fr/greencodeinitiative/java/checks/AvoidEnergyConsumingMethodsTest.java
new file mode 100644
index 0000000..b2c23f1
--- /dev/null
+++ b/src/test/java/fr/greencodeinitiative/java/checks/AvoidEnergyConsumingMethodsTest.java
@@ -0,0 +1,33 @@
+/*
+ * ecoCode - Java language - Provides rules to reduce the environmental footprint of your Java programs
+ * Copyright © 2023 Green Code Initiative (https://www.ecocode.io)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package fr.greencodeinitiative.java.checks;
+
+import org.junit.jupiter.api.Test;
+import org.sonar.java.checks.verifier.CheckVerifier;
+
+class AvoidEnergyConsumingMethodsTest {
+
+ @Test
+ void test() {
+ CheckVerifier.newVerifier()
+ .onFile("src/test/files/AvoidEnergyConsumingMethodsCheck.java")
+ .withCheck(new AvoidEnergyConsumingMethods())
+ .verifyIssues();
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/fr/greencodeinitiative/java/checks/ForceLazyFetchTypeForJPATest.java b/src/test/java/fr/greencodeinitiative/java/checks/ForceLazyFetchTypeForJPATest.java
new file mode 100644
index 0000000..8e11261
--- /dev/null
+++ b/src/test/java/fr/greencodeinitiative/java/checks/ForceLazyFetchTypeForJPATest.java
@@ -0,0 +1,33 @@
+/*
+ * ecoCode - Java language - Provides rules to reduce the environmental footprint of your Java programs
+ * Copyright © 2023 Green Code Initiative (https://www.ecocode.io)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package fr.greencodeinitiative.java.checks;
+
+import org.junit.jupiter.api.Test;
+import org.sonar.java.checks.verifier.CheckVerifier;
+
+class ForceLazyFetchTypeForJPATest {
+
+ @Test
+ void test() {
+ CheckVerifier.newVerifier()
+ .onFile("src/test/files/ForceLazyFetchTypeForJPACheck.java")
+ .withCheck(new ForceLazyFetchTypeForJPA())
+ .verifyIssues();
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/fr/greencodeinitiative/java/checks/MakeNonReassignedVariablesConstantsTest.java b/src/test/java/fr/greencodeinitiative/java/checks/MakeNonReassignedVariablesConstantsTest.java
new file mode 100644
index 0000000..054da3e
--- /dev/null
+++ b/src/test/java/fr/greencodeinitiative/java/checks/MakeNonReassignedVariablesConstantsTest.java
@@ -0,0 +1,33 @@
+/*
+ * ecoCode - Java language - Provides rules to reduce the environmental footprint of your Java programs
+ * Copyright © 2023 Green Code Initiative (https://www.ecocode.io)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package fr.greencodeinitiative.java.checks;
+
+import org.junit.jupiter.api.Test;
+import org.sonar.java.checks.verifier.CheckVerifier;
+
+class MakeNonReassignedVariablesConstantsTest {
+
+ @Test
+ void test() {
+ CheckVerifier.newVerifier()
+ .onFile("src/test/files/MakeNonReassignedVariablesConstantsCheck.java")
+ .withCheck(new MakeNonReassignedVariablesConstants())
+ .verifyIssues();
+ }
+
+}
\ No newline at end of file