I'm trying to enable LoadTimeWeaving in spring boot project.
What I've done so far:
Upon starting the application I'm getting the following error:
13:27:55.492 [main] INFO o.s.data.repository.config.RepositoryConfigurationExtensionSupport - Spring Data JPA - Could not safely identify store assignment for repository candidate interface com.something.SomethingRepository; If you want this repository to be a JPA repository, consider annotating your entities with one of these annotations: jakarta.persistence.Entity, jakarta.persistence.MappedSuperclass (preferred), or consider extending one of the following types with your repository: org.springframework.data.jpa.repository.JpaRepository
Notes:
Observations:
org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtension#getIdentifyingAnnotations
gets Entity.class
, and MappedSuperClass.class
from class loader ClassLoaders.AppClassLoader
.@Override
protected Collection<Class<? extends Annotation>> getIdentifyingAnnotations() {
return Arrays.asList(Entity.class, MappedSuperclass.class);
}
private static boolean isMappingForType(AnnotationTypeMapping mapping,
AnnotationFilter annotationFilter, @Nullable Object requiredType) {
Class<? extends Annotation> actualType = mapping.getAnnotationType();
return (!annotationFilter.matches(actualType) &&
(requiredType == null || actualType == requiredType || actualType.getName().equals(requiredType)));
}
InspectionClassLoader
as LazyJvmAgent.isActive(loader.getClassLoader())
returns true. @Override
protected ClassLoader getConfigurationInspectionClassLoader(ResourceLoader loader) {
ClassLoader classLoader = loader.getClassLoader();
return classLoader != null && LazyJvmAgent.isActive(loader.getClassLoader())
? new InspectionClassLoader(loader.getClassLoader())
: loader.getClassLoader();
}
So my question is: What is it that I'm missing here? Shouldn't they use the same class loader if we need to check equality like that? I would change all CrudRepository to JpaRepository but it might create some other issues it kind of looks hackish to me as it should already work with @Entity annotation. Any insights on this?
Edit: Note: I have multiple data source in this project.
The problem is simply that spring-instrument
is an agent which attaches another agent - namely aspectjweaver
- later during runtime. Invesdwin does a similar thing, trying to avoid the java agent on the command line altogether.
The solution is to simply do it right and use -javaagent:/path/to/aspectjweaver-1.9.22.jar
(the version used by your sample program) directly instead of spring-instrument
. I tried with your sample, changing one line in your build.gradle as follows:
jvmArgs(["-javaagent:/path/to/aspectjweaver-1.9.22.jar"])
It works beautifully. @Entity
and CrudRepository
are enough, just as you like it. The agent needs to be attached during the start of the JVM, then there are no classloader problems.
BTW, if you want to embed the AspectJ weaver or any other agent into an executable Spring Boot JAR and auto-start it from there without any extra command line arguments, take a look at Agent Embedder Maven Plugin. I am the maintainer, and no, I did not port it to Gradle.