Monday, April 10, 2023

How to fix "not a managed type exception" in JPA? [Solution]

Hello folks, JPA (Java Persistence API) is a widely used technology in Java applications for object-relational mapping (ORM) and working with databases. However, when using JPA, you may encounter the "not a managed type" exception, which is a common error that occurs when JPA fails to recognize an entity class as a managed type. This exception can occur due to various reasons, such as incorrect package or class names, missing annotations, or misconfiguration of JPA settings. Fixing this error requires identifying the root cause and taking appropriate steps to resolve it. In this article, we will explore different strategies and solutions to fix the "not a managed type" exception in JPA, helping you overcome this hurdle and successfully work with JPA in your Java applications.


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.

How to fix "not a managed type exception" in JPA? [Solution]


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.