Consider JPA Id annotations for domain id repo reconciler
This commit is contained in:
@@ -26,7 +26,9 @@ public class Annotations {
|
|||||||
public static final String REPOSITORY = "org.springframework.stereotype.Repository";
|
public static final String REPOSITORY = "org.springframework.stereotype.Repository";
|
||||||
public static final String REPOSITORY_DEFINITION = "org.springframework.data.repository.RepositoryDefinition";
|
public static final String REPOSITORY_DEFINITION = "org.springframework.data.repository.RepositoryDefinition";
|
||||||
public static final String NO_REPO_BEAN = "org.springframework.data.repository.NoRepositoryBean";
|
public static final String NO_REPO_BEAN = "org.springframework.data.repository.NoRepositoryBean";
|
||||||
public static final String ENTITY_ID = "org.springframework.data.annotation.Id";
|
public static final String SPRING_ENTITY_ID = "org.springframework.data.annotation.Id";
|
||||||
|
public static final String JPA_JAKARTA_ENTITY_ID = "jakarta.persistence.Id";
|
||||||
|
public static final String JPA_JAVAX_ENTITY_ID = "javax.persistence.Id";
|
||||||
|
|
||||||
public static final String AUTOWIRED = "org.springframework.beans.factory.annotation.Autowired";
|
public static final String AUTOWIRED = "org.springframework.beans.factory.annotation.Autowired";
|
||||||
public static final String INJECT = "javax.inject.Inject";
|
public static final String INJECT = "javax.inject.Inject";
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import static org.springframework.ide.vscode.commons.java.SpringProjectUtil.spri
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -325,16 +326,17 @@ public class EntityIdForRepoReconciler implements JdtAstReconciler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static ITypeBinding findAnnotatedIdType(ITypeBinding type, Set<String> visited) {
|
private static ITypeBinding findAnnotatedIdType(ITypeBinding type, Set<String> visited) {
|
||||||
|
List<String> idAnnotations = List.of(Annotations.SPRING_ENTITY_ID, Annotations.JPA_JAKARTA_ENTITY_ID, Annotations.JPA_JAVAX_ENTITY_ID);
|
||||||
for (IVariableBinding m : type.getDeclaredFields()) {
|
for (IVariableBinding m : type.getDeclaredFields()) {
|
||||||
String s = fieldSignature(m);
|
String s = fieldSignature(m);
|
||||||
if (!visited.contains(s) && isAnnotationCompatible(m.getAnnotations(), Annotations.ENTITY_ID)) {
|
if (!visited.contains(s) && isAnnotationCompatible(m.getAnnotations(), idAnnotations)) {
|
||||||
return m.getType();
|
return m.getType();
|
||||||
}
|
}
|
||||||
visited.add(s);
|
visited.add(s);
|
||||||
}
|
}
|
||||||
for (IMethodBinding m : type.getDeclaredMethods()) {
|
for (IMethodBinding m : type.getDeclaredMethods()) {
|
||||||
String s = methodSignature(m);
|
String s = methodSignature(m);
|
||||||
if (!visited.contains(s) && isAnnotationCompatible(m.getAnnotations(), Annotations.ENTITY_ID)) {
|
if (!visited.contains(s) && isAnnotationCompatible(m.getAnnotations(), idAnnotations)) {
|
||||||
return m.getReturnType();
|
return m.getReturnType();
|
||||||
}
|
}
|
||||||
visited.add(s);
|
visited.add(s);
|
||||||
@@ -349,10 +351,10 @@ public class EntityIdForRepoReconciler implements JdtAstReconciler {
|
|||||||
return f.getName();
|
return f.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isAnnotationCompatible(IAnnotationBinding[] annotations, String fqName) {
|
private static boolean isAnnotationCompatible(IAnnotationBinding[] annotations, Collection<String> fqNames) {
|
||||||
for (IAnnotationBinding a : annotations) {
|
for (IAnnotationBinding a : annotations) {
|
||||||
if (AnnotationHierarchies.findTransitiveSuperAnnotationBindings(a)
|
if (AnnotationHierarchies.findTransitiveSuperAnnotationBindings(a)
|
||||||
.anyMatch(at -> fqName.equals(at.getAnnotationType().getQualifiedName()))) {
|
.anyMatch(at -> fqNames.contains(at.getAnnotationType().getQualifiedName()))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -330,6 +330,42 @@ public class EntityIdForRepoReconcilerTest extends BaseReconcilerTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void inheritance_invalidDomainId_string_number_jakarta_id() throws Exception {
|
||||||
|
|
||||||
|
Path employeeSource = createFile("Customer.java", """
|
||||||
|
package demo;
|
||||||
|
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
|
||||||
|
public class Customer {
|
||||||
|
@Id String customerNumber;
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
|
||||||
|
String source = """
|
||||||
|
package demo;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.Repository;
|
||||||
|
|
||||||
|
interface CustomerRepository extends Repository<Customer, Long> {}
|
||||||
|
""";
|
||||||
|
List<ReconcileProblem> problems = reconcile("CustomerRepository.java", source, false, employeeSource);
|
||||||
|
|
||||||
|
assertEquals(1, problems.size());
|
||||||
|
|
||||||
|
ReconcileProblem problem = problems.get(0);
|
||||||
|
|
||||||
|
assertEquals(Boot2JavaProblemType.DOMAIN_ID_FOR_REPOSITORY, problem.getType());
|
||||||
|
|
||||||
|
String markedStr = source.substring(problem.getOffset(), problem.getOffset() + problem.getLength());
|
||||||
|
assertEquals("Long", markedStr);
|
||||||
|
assertEquals("Expected Domain ID type is 'java.lang.String'", problem.getMessage());
|
||||||
|
|
||||||
|
assertEquals(0, problem.getQuickfixes().size());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void inheritance_invalidDomainId_string_number_2() throws Exception {
|
void inheritance_invalidDomainId_string_number_2() throws Exception {
|
||||||
|
|
||||||
@@ -765,7 +801,7 @@ public class EntityIdForRepoReconcilerTest extends BaseReconcilerTest {
|
|||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
|
|
||||||
public record Employee(@Id String id) {};
|
public record Employee(@Id String employeeId) {};
|
||||||
""");
|
""");
|
||||||
|
|
||||||
String source = """
|
String source = """
|
||||||
@@ -792,6 +828,40 @@ public class EntityIdForRepoReconcilerTest extends BaseReconcilerTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void invalid_DomainId_record_1() throws Exception {
|
||||||
|
|
||||||
|
Path employeeSource = createFile("Employee.java", """
|
||||||
|
package demo;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
|
||||||
|
public record Employee(@Id String employeeId) {};
|
||||||
|
""");
|
||||||
|
|
||||||
|
String source = """
|
||||||
|
package demo;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.Repository;
|
||||||
|
|
||||||
|
interface EmployeeRepository extends Repository<Employee, Number>{}
|
||||||
|
""";
|
||||||
|
List<ReconcileProblem> problems = reconcile("EmployeeRepository.java", source, false, employeeSource);
|
||||||
|
|
||||||
|
assertEquals(1, problems.size());
|
||||||
|
|
||||||
|
ReconcileProblem problem = problems.get(0);
|
||||||
|
|
||||||
|
assertEquals(Boot2JavaProblemType.DOMAIN_ID_FOR_REPOSITORY, problem.getType());
|
||||||
|
|
||||||
|
String markedStr = source.substring(problem.getOffset(), problem.getOffset() + problem.getLength());
|
||||||
|
assertEquals("Number", markedStr);
|
||||||
|
assertEquals("Expected Domain ID type is 'java.lang.String'", problem.getMessage());
|
||||||
|
|
||||||
|
assertEquals(0, problem.getQuickfixes().size());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void valid_DomainId_record() throws Exception {
|
void valid_DomainId_record() throws Exception {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user