Before we dig into the possible solutions to this problem, let’s have a look at why such an exception takes place at first. We will try to demonstrate it with the help of a simple Spring Boot project.
Below is the directory structure of our Spring Boot project.
├── java
│ └── com
│ └── java67
│ ├── entity
│ │ └── Student.java
│ └── schoolsystem
│ ├── controller
│ │ └── StudentController.java
│ ├── exceptions
│ │ └── GlobalExceptionHandler.java
│ ├── GettingStarted.java
│ ├── repo
│ │ └── StudentRepo.java
│ └── service
│ └── StudentService.java
└── resources
├── application.yml
├── companies.txt
├── static
└── templates
└── index.html
As you can see, we have only one entity Student under com.java67.entity package. Where as our main application is residing inside com.java67.schoolsystem package. When we run our application it results in below error
org.springframework.beans.factory.UnsatisfiedDependencyException:
Not a managed type:
class com.java67.entity.Student
Why this error?
The reason for this exception is that the Spring Boot framework could not find the Student entity. You might ask, why spring is unable to find the Student’s entity. The answer is very simple, spring by default expects entities to be in the same package or child packages.
Whereas the Student entity is neither in schoolsystem package nor in its child, thus, it fails to deliver the expected result.
3 ways to solve "not a managed type exception" in JPA
There are three possible solutions to it
Move the entity classes into the main package (the one containing Spring Boot's main class).
Rename the package containing the main class.
Explicitly scan the entity package using @EntityScan annotation.
Let’s describe each one in detail here.
1. Place entity class inside the main package
├── java
│ └── com
│ └── java67
│ └── schoolsystem
│ ├── controller
│ │ └── StudentController.java
│ ├── entity
│ │ └── Student.java
│ ├── exceptions
│ │ └── GlobalExceptionHandler.java
│ ├── GettingStarted.java
│ ├── repo
│ │ └── StudentRepo.java
│ └── service
│ └── StudentService.java
└── resources
├── application.yml
├── companies.txt
├── static
└── templates
└── index.html
We have placed the Student entity inside the main package (i.e. schoolsystem). With the above modifications, our application starts as usual.
: HHH000490: Using JtaPlatform implementation:
: Initialized JPA EntityManagerFactory for persistence unit 'default'
: spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
: Adding welcome page template: index
: Tomcat started on port(s): 8080 (http) with context path ''
com.java67.schoolsystem.GettingStarted : Started GettingStarted in 3.827 seconds
2. Renaming the package
We can achieved the same goal by re-factoring the package. Spring boot’s main application is unable to locate the Student entity due to residing in a different package. We can make it to reside as a root package. The updated directory structure can be seen below.
├── java
│ └── com
│ └── java67
│ ├── controller
│ │ └── StudentController.java
│ ├── entity
│ │ └── Student.java
│ ├── exceptions
│ │ └── GlobalExceptionHandler.java
│ ├── GettingStarted.java
│ ├── repo
│ │ └── StudentRepo.java
│ ├── schoolsystem
│ └── service
│ └── StudentService.java
└── resources
├── application.yml
├── companies.txt
├── static
└── templates
└── index.html
As you can see, the spring boot application class has been refactored from the com.java67.schoolsystem package to com.java67. With this adjustment, the Student entity, which is contained in the com.java67.entity package may now be accessed by our main application.
3. @EntityScan
Sometimes, our application is complex and large enough for re-factor. Here comes Spring framework’s EntityScan annotation into the picture. We can explicitly ask the spring application to search in the specified package. Let’s see this in action.
├── java
│ └── com
│ └── java67
│ ├── entity
│ │ └── Student.java
│ └── schoolsystem
│ ├── controller
│ │ └── StudentController.java
│ ├── exceptions
│ │ └── GlobalExceptionHandler.java
│ ├── GettingStarted.java
│ ├── repo
│ │ └── StudentRepo.java
│ └── service
│ └── StudentService.java
└── resources
├── application.yml
├── companies.txt
├── static
└── templates
└── index.html
Student.java
package com.java67.entity;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Entity
@Data
@Table(name = "students")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@NotNull
private int age;
@NotNull
private String name;
}
Main Application
package com.java67.schoolsystem;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import java.io.IOException;
@SpringBootApplication
@EntityScan("com.java67.entity")
public class GettingStarted {
public static void main(String[] args) throws IOException {
SpringApplication.run(GettingStarted.class, args);
}
}
What is @EntityScan annotation? what does it do?
When entity classes are not included in the main application package or any of its child packages, the @EntityScan annotation is utilized. In this instance, the primary configuration class's @EntityScan annotation would contain a declaration of the package or set of packages.
With this, Spring will know where to look for the entities needed by our application.
In our example, we have specified Spring to search under package com.java67.entity. In case you have more than one package to search into, we can specify it as shown below.
@EntityScan({"com.something.entity_1","com.somthing.entity_2"})
That's all about how to fix "not a managed type exception" in JPA. The "not a managed type" exception in JPA can be a challenging issue to troubleshoot and resolve. However, with a good understanding of JPA entity management and configuration, along with careful examination of your code and settings, you can successfully fix this error and continue working with JPA in your Java applications.
Remember to double-check your entity class names, package names, annotations, and JPA settings to ensure they are correctly configured and aligned with your application's requirements. Additionally, be sure to review any potential classpath or dependency issues that may be causing the exception.
By diligently investigating and addressing the root cause of the error, you can overcome this obstacle and leverage the full capabilities of JPA for effective database persistence in your Java projects.With this, our brief article concludes.
Here, we've learned three distinct methods for resolving the issue i.e. not a managed type JPA exception. I'm hoping the methods I've just described will enable you to solve the underlying issue easily.
No comments:
Post a Comment
Feel free to comment, ask questions if you have any doubt.