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

Crjvm205 #122

Open
wants to merge 47 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
8969840
Create ForceLazyFetchTypeUse.java
AntoineMeheut Apr 5, 2023
5d3d380
Merge pull request #1 from AntoineMeheut/CRJVM205
AntoineMeheut Apr 5, 2023
bda60fe
Creation of html and json files
AntoineMeheut Apr 5, 2023
36cef91
WKR-Add Rule structure dev
WalidKrifi Apr 5, 2023
0bdc73d
update CRJVM250.html
AntoineMeheut Apr 5, 2023
2ed3514
WKR-Add access to annotation
WalidKrifi Apr 5, 2023
1d68d3f
WKR-Add trying access to arguments
WalidKrifi Apr 5, 2023
7409bc6
WKR-Add Rule structure dev
WalidKrifi Apr 5, 2023
2341685
Update tests classes
AntoineMeheut Apr 5, 2023
580dc34
WKR-Add access to annotation
WalidKrifi Apr 5, 2023
d64c35b
WKR-Add trying access to fetch
WalidKrifi Apr 5, 2023
50fe804
Modify method name avoid compilation error
Apr 5, 2023
d87da8c
Merge pull request #3 from AntoineMeheut/CRJVM205_SLS
AntoineMeheut Apr 5, 2023
6619a8f
WKR- first version
WalidKrifi Apr 5, 2023
2187338
Merge branch 'CRJVM205' into CRJVM205-WKR
AntoineMeheut Apr 5, 2023
ef11e33
Merge team build
AntoineMeheut Apr 5, 2023
c4f8f0c
Merge branch 'CRJVM205-WKR' of https://github.com/AntoineMeheut/ecoCo…
AntoineMeheut Apr 5, 2023
782e39f
Merge pull request #2 from AntoineMeheut/CRJVM205-WKR
sebals Apr 5, 2023
6e9fee7
WKR- second version
WalidKrifi Apr 5, 2023
4188277
WKR- second version
WalidKrifi Apr 5, 2023
c2983a4
WKR- second version
WalidKrifi Apr 5, 2023
58055ab
Correct merge
AntoineMeheut Apr 5, 2023
08f8145
Merge branch 'CRJVM205-WKR' of https://github.com/AntoineMeheut/ecoCo…
AntoineMeheut Apr 5, 2023
7fa808c
Modify table names and column name
Apr 5, 2023
44b9e80
Merge remote-tracking branch 'origin/CRJVM205-WKR' into CRJVM205-WKR
Apr 5, 2023
a5c0fb0
Merge pull request #5 from AntoineMeheut/CRJVM205-WKR
AntoineMeheut Apr 5, 2023
d3f2024
Merge pull request #4 from AntoineMeheut/CRJVM205
AntoineMeheut Apr 5, 2023
eeaaadc
WKR- second version
WalidKrifi Apr 5, 2023
bb43a16
for testing
dirdr Apr 5, 2023
071d082
delete files
dirdr Apr 5, 2023
06d2e10
Merge pull request #6 from AntoineMeheut/CRJVM205-WKR
AntoineMeheut Apr 5, 2023
34be768
Change rule number to EC80
AntoineMeheut Apr 5, 2023
2bf8921
Change rule number for EC80
AntoineMeheut Apr 5, 2023
2c8e50d
Add new test file and test
Apr 5, 2023
8f978ea
WKR- Add check of default values
WalidKrifi Apr 5, 2023
a798cab
Merge pull request #7 from AntoineMeheut/CRJVM205-WKR
AntoineMeheut Apr 5, 2023
bdcf8ea
Update JavaCheckRegistrarTest.java
AntoineMeheut Apr 5, 2023
ed6b6c4
Merge pull request #8 from AntoineMeheut/CRJVM205
AntoineMeheut Apr 5, 2023
55677d7
[CRJVM205] refactoring code
dirdr Apr 6, 2023
94fde4d
[CRJVM205] added public keyword to compile again!
dirdr Apr 6, 2023
5dd3483
[CRJVM205] code clean up
dirdr Apr 6, 2023
3785981
[CRJVM205] changed from pull request review
dirdr Apr 7, 2023
ba397b1
Merge branch 'main' into CRJVM205
AntoineMeheut Apr 7, 2023
04d5ec7
Merge branch 'main' into CRJVM205
dedece35 May 9, 2023
beee006
[CRJVM205] code review fix
dirdr May 17, 2023
ad66c3d
Merge branch 'main' into CRJVM205
dirdr May 17, 2023
a8e886a
Merge branch 'main' into CRJVM205
dedece35 Jun 27, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,7 @@
import java.util.Collections;
import java.util.List;

import fr.greencodeinitiative.java.checks.ArrayCopyCheck;
import fr.greencodeinitiative.java.checks.AvoidConcatenateStringsInLoop;
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.AvoidSpringRepositoryCallInLoopCheck;
import fr.greencodeinitiative.java.checks.AvoidStatementForDMLQueries;
import fr.greencodeinitiative.java.checks.AvoidUsageOfStaticCollections;
import fr.greencodeinitiative.java.checks.AvoidUsingGlobalVariablesCheck;
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.UnnecessarilyAssignValuesToVariables;
import fr.greencodeinitiative.java.checks.UseCorrectForLoop;
import fr.greencodeinitiative.java.checks.*;
import org.sonar.plugins.java.api.JavaCheck;

public final class RulesList {
Expand Down Expand Up @@ -77,7 +59,8 @@ public static List<Class<? extends JavaCheck>> getJavaChecks() {
AvoidUsingGlobalVariablesCheck.class,
AvoidSetConstantInBatchUpdate.class,
FreeResourcesOfAutoCloseableInterface.class,
AvoidMultipleIfElseStatement.class
AvoidMultipleIfElseStatement.class,
ForceUsingLazyFetchTypeInJPAEntity.class
));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package fr.greencodeinitiative.java.checks;

import org.sonar.check.Priority;
import org.sonar.check.Rule;
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
import org.sonar.plugins.java.api.tree.*;
import org.sonar.plugins.java.api.tree.Tree.Kind;

import java.util.List;

@Rule(key = "EC80", name = "Developpement",
dedece35 marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

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

there is a new way to declare configuration of one rule : please see other rules as example

description = ForceUsingLazyFetchTypeInJPAEntity.MESSAGERULE,
priority = Priority.MINOR,
tags = {"bug"})
public class ForceUsingLazyFetchTypeInJPAEntity extends IssuableSubscriptionVisitor {

protected static final String MESSAGERULE = "Force the use of LAZY FetchType";
private static final String EAGER_KEYWORD = "EAGER";
private static final String FETCH_KEYWORD = "fetch";
private static final String ONE_TO_MANY = "OneToMany";
private static final String MANY_TO_ONE = "ManyToOne";
private static final String ONE_TO_ONE = "OneToOne";
private static final String MANY_TO_MANY = "ManyToMany";

@Override
public List<Kind> nodesToVisit() {
return List.of(Kind.VARIABLE);
}

@Override
public void visitNode(Tree tree) {
VariableTree variableTree = (VariableTree) tree;
List<AnnotationTree> annotations = variableTree.modifiers().annotations();
Copy link
Member

Choose a reason for hiding this comment

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

did you check if null pointer could be raised here ?

Copy link

Choose a reason for hiding this comment

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

After searching, ModifiersTree is not annotated @nullable. Accessing annotations by this interface method is normally safe, so no intermediate checks are required.

// get all annotations on the attribute
for (AnnotationTree annotationTree : annotations) {
if (!needToCheckExplicitAnnotation(annotationTree.annotationType().symbolType().name())) {
// no Explicit annotation (@OneToMany, @ManyToOne, @ManyToMany, @OneToOne) was found,
// and we don't need to investigate further
continue;
}
Arguments arguments = annotationTree.arguments();
performsCheck(arguments, annotationTree, tree);
}
}

/**
* perform the check for two case :
* fetch keyword is found -> parse the annotation argument and search for eager keyword
* fetch keyword was not found -> we use the default value of fetch type by join type :
* OneToMany: Lazy
* ManyToOne: Eager
* ManyToMany: Lazy
* OneToOne: Eager
* reporting the issues if necessary
*/
private void performsCheck(Arguments arguments, AnnotationTree annotationTree, Tree tree) {
Copy link
Member

Choose a reason for hiding this comment

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

here, no need to give arguments as input parameter because it already is present inside annotationTree input parameter

boolean fetchFound = false;
for (ExpressionTree argument : arguments) {
AssignmentExpressionTree assignmentExpression = (AssignmentExpressionTree) argument;
IdentifierTree variable = (IdentifierTree) assignmentExpression.variable();

if (!FETCH_KEYWORD.equals(variable.name())) {
// no need to continue checking this argument
continue;
}
String fetchValue = ((MemberSelectExpressionTree) assignmentExpression.expression()).identifier().name();
fetchFound = true;
if (EAGER_KEYWORD.equals(fetchValue)) {
reportIssue(tree, MESSAGERULE);
}
}
//- The default case of the ManyToOne and the OneToOne
// the fetch keyword is not explicit
if (fetchFound) {
return;
}
String symbolType = annotationTree.annotationType().symbolType().name();
if ((MANY_TO_ONE.equals(symbolType) || ONE_TO_ONE.equals(symbolType))) {
reportIssue(tree, MESSAGERULE);
}
}

/**
* @param symbolType the annotation type name : @OneToMany, @ManyToOne...
* @return true if searched annotation was found and checks need to be performed
*/
private boolean needToCheckExplicitAnnotation(String symbolType) {
return ONE_TO_MANY.equals(symbolType)
|| MANY_TO_ONE.equals(symbolType)
|| ONE_TO_ONE.equals(symbolType)
|| MANY_TO_MANY.equals(symbolType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<p>Consider using LAZY mode on your FetchType for collections in JPA type entities. This will reduce the amount of data loaded into memory.</p>

<h2>Non-compliant Code Example</h2>
<pre>
@Entity
@Table(name = "purchaseOrder")
public class Order implements Serializable {

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

...

}

</pre>
<h2>Compliant Code Example</h2>
<pre>
@Entity
@Table(name = "purchaseOrder")
public class Order implements Serializable {

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

...

}

</pre>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"title": "Force the use of FetchType LAZY on collections in Entity JPA",
Copy link
Member

Choose a reason for hiding this comment

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

now, it isn't the good way to declare rule properties but inside ecocode-rules-specifications (please see another rule as example)

"type": "CODE_SMELL",
"status": "ready",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "5min"
},
"tags": [
"eco-design",
"performance",
"bug",
"ecocode"
],
"defaultSeverity": "Minor"
}
26 changes: 26 additions & 0 deletions java-plugin/src/test/files/ForceLazyFetchTypeUseAllInOne.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

Copy link
Member

Choose a reason for hiding this comment

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

why don't you give all use cases in a single file ? why several test files ?

@Entity
@Table(name = "myTable")
public class ForceLazyFetchTypeUseAllInOne implements Serializable {

@OneToMany(mappedBy = "myOrders", fetch = FetchType.EAGER) // Noncompliant {{Force the use of LAZY FetchType}}
private Set<OrderItem> items = new HashSet<OrderItem>();

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

@Column(name = "ORDER", length = 50, nullable = false, unique = false)
private Set<OrderItem> items = new HashSet<OrderItem>();

Copy link
Member

Choose a reason for hiding this comment

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

please as a new use case with default value for fetch keywork (thus, without "fetch" variable assigned)

}
20 changes: 20 additions & 0 deletions java-plugin/src/test/files/ForceLazyFetchTypeUseCompliant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

@Entity
@Table(name = "myTable")
public class ForceLazyFetchTypeUseCompliant implements Serializable {

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

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

@Entity
@Table(name = "myTable")
public class ForceLazyFetchTypeUseFalse implements Serializable {

@ManyToOne // Noncompliant {{Force the use of LAZY FetchType}}
private Order order;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

@Entity
@Table(name = "myTable")
public class ForceLazyFetchTypeUseFalse implements Serializable {

@OneToOne // Noncompliant {{Force the use of LAZY FetchType}}
private OrderInformation orderInformations;

}
20 changes: 20 additions & 0 deletions java-plugin/src/test/files/ForceLazyFetchTypeUseFalseTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

@Entity
@Table(name = "myTable")
public class ForceLazyFetchTypeUseFalseTest implements Serializable {
Copy link
Member

Choose a reason for hiding this comment

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

please dont use suffix "Test" for POJO classes to not confuse with Unit Test class


@Column(name = "ORDER", length = 50, nullable = false, unique = false)
private Set<OrderItem> items = new HashSet<OrderItem>();

}
20 changes: 20 additions & 0 deletions java-plugin/src/test/files/ForceLazyFetchTypeUseManyToOne.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

@Entity
@Table(name = "myTable")
public class ForceLazyFetchTypeUseFalseTest implements Serializable {
Copy link
Member

Choose a reason for hiding this comment

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

please dont use suffix "Test" for POJO classes to not confuse with Unit Test class


@ManyToOne(fetch = FetchType.EAGER) // Noncompliant {{Force the use of LAZY FetchType}}
private Order order;

}
20 changes: 20 additions & 0 deletions java-plugin/src/test/files/ForceLazyFetchTypeUseNonCompliant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

@Entity
@Table(name = "myTable")
public class ForceLazyFetchTypeUseNonCompliant implements Serializable {

@OneToMany(mappedBy = "myOrders", fetch = FetchType.EAGER) // Noncompliant {{Force the use of LAZY FetchType}}
private Set<OrderItem> items = new HashSet<OrderItem>();

}
20 changes: 20 additions & 0 deletions java-plugin/src/test/files/ForceLazyFetchTypeUseOneToOne.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

@Entity
@Table(name = "myTable")
public class ForceLazyFetchTypeUseFalseTest implements Serializable {

@OneToOne(fetch = FetchType.EAGER) // Noncompliant {{Force the use of LAZY FetchType}}
private OrderInformation orderInformations;

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ void checkNumberRules() {
final JavaCheckRegistrar registrar = new JavaCheckRegistrar();
registrar.register(context);

assertThat(context.checkClasses()).hasSize(19);
assertThat(context.checkClasses()).hasSize(20);
Copy link
Member

Choose a reason for hiding this comment

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

maybe value has to be changed. to recheck locally, please

assertThat(context.testCheckClasses()).isEmpty();
}
}
Loading