'SpringBoot - Server Won't Start; Unknown 'mappedBy' Error
I'm relatively new to SpringBoot, and I've been following this tutorial on SpringBoot + React on Udemy called "Full Stack Project: Spring Boot 2.0, ReactJS, Redux."
I am no longer able to start my server. I am getting this error:
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2022-02-22 07:58:57.885 ERROR 33860 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Unknown mappedBy in: com.jonjackson.ppmtool.domain.Backlog.projectTasks, referenced property unknown: java.util.List.backlog
...
Caused by: org.hibernate.AnnotationException: Unknown mappedBy in: com.jonjackson.ppmtool.domain.Backlog.projectTasks, referenced property unknown: java.util.List.backlog
I think this error may have something to do with the value that I am passing in the mappedBy in a @OneToOne or @ManyToOne annotation, but I am not sure what I have done differently than the tutorial. Does anyone see the issue here?
The files that are referenced in the error are:
ProjectTask.java
package com.jonjackson.ppmtool.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.util.Date;
@Entity
public class ProjectTask {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(updatable = false, unique = true)
private String projectSequence;
//header for projectTask
@NotBlank(message = "Please include a project summary")
private String summary;
private String acceptanceCriteria;
private String status;
private Integer priority;
@JsonFormat(pattern = "yyyy-mm-dd")
private Date dueDate;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="backlog_id", updatable = false, nullable = false)
@JsonIgnore
private Backlog backlog;
@Column(updatable = false)
private String projectIdentifier;
@JsonFormat(pattern = "yyyy-mm-dd")
private Date create_At;
@JsonFormat(pattern = "yyyy-mm-dd")
private Date update_At;
public ProjectTask(){
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getProjectSequence() {
return projectSequence;
}
public void setProjectSequence(String projectSequence) {
this.projectSequence = projectSequence;
}
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getAcceptanceCriteria() {
return acceptanceCriteria;
}
public void setAcceptanceCriteria(String acceptanceCriteria) {
this.acceptanceCriteria = acceptanceCriteria;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Integer getPriority() {
return priority;
}
public void setPriority(Integer priority) {
this.priority = priority;
}
public Date getDueDate() {
return dueDate;
}
public void setDueDate(Date dueDate) {
this.dueDate = dueDate;
}
public String getProjectIdentifier() {
return projectIdentifier;
}
public void setProjectIdentifier(String projectIdentifier) {
this.projectIdentifier = projectIdentifier;
}
public Date getCreate_At() {
return create_At;
}
public void setCreate_At(Date create_At) {
this.create_At = create_At;
}
public Date getUpdate_At() {
return update_At;
}
public void setUpdate_At(Date update_At) {
this.update_At = update_At;
}
public Backlog getBacklog() {
return backlog;
}
public void setBacklog(Backlog backlog) {
this.backlog = backlog;
}
@PrePersist
protected void onCreate(){
this.create_At = new Date();
}
@PreUpdate
protected void onUpdate(){
this.update_At = new Date();
}
@Override
public String toString() {
return "ProjectTask{" +
"id=" + id +
", projectSequence='" + projectSequence + '\'' +
", summary='" + summary + '\'' +
", acceptanceCriteria='" + acceptanceCriteria + '\'' +
", status='" + status + '\'' +
", priority=" + priority +
", dueDate=" + dueDate +
", projectIdentifier='" + projectIdentifier + '\'' +
", create_At=" + create_At +
", update_At=" + update_At +
'}';
}
}
Backlog.java
package com.jonjackson.ppmtool.domain;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
public class Backlog {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Integer PTSequence = 0;
private String projectIdentifier;
@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name="project_id", nullable = false)
@JsonIgnore
private Project project;
//OneToMany with projecttasks (a backlog can have one or more projecttasks, but a projecttask can belong to one project)
@OneToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER, mappedBy = "backlog", orphanRemoval = true)
private List<ProjectTask> projectTasks = new ArrayList<>();
public Backlog(){
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getPTSequence() {
return PTSequence;
}
public void setPTSequence(Integer PTSequence) {
this.PTSequence = PTSequence;
}
public String getProjectIdentifier() {
return projectIdentifier;
}
public void setProjectIdentifier(String projectIdentifier) {
this.projectIdentifier = projectIdentifier;
}
public Project getProject() {
return project;
}
public void setProject(Project project) {
this.project = project;
}
public List<ProjectTask> getProjectTasks() {
return projectTasks;
}
public void setProjectTasks(List<ProjectTask> projectTasks) {
this.projectTasks = projectTasks;
}
}
and here is the main Project class:
Project.java
package com.jonjackson.ppmtool.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.util.Date;
@Entity
public class Project {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank(message = "Project name is required")
private String projectName;
@NotBlank(message = "Project Identifier is required")
@Size(min = 4, max = 5, message = "Please use 4 to 5 characters")
@Column(updatable = false, unique = true)
private String projectIdentifier; //adding custom identifier for Project {}
@NotBlank(message = "Project Description is required")
private String description;
@JsonFormat(pattern = "yyyy-mm-dd")
private Date start_date;
@JsonFormat(pattern = "yyyy-mm-dd")
private Date end_date;
@JsonFormat(pattern = "yyyy-mm-dd")
@Column(updatable = false)
private Date created_at;
@JsonFormat(pattern = "yyyy-mm-dd")
private Date updated_at;
@OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "project")
private Backlog backlog;
public Project() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public String getProjectIdentifier() {
return projectIdentifier;
}
public void setProjectIdentifier(String projectIdentifier) {
this.projectIdentifier = projectIdentifier;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getStart_date() {
return start_date;
}
public void setStart_date(Date start_date) {
this.start_date = start_date;
}
public Date getEnd_date() {
return end_date;
}
public void setEnd_date(Date end_date) {
this.end_date = end_date;
}
public Date getCreated_at() {
return created_at;
}
public void setCreated_at(Date created_at) {
this.created_at = created_at;
}
public Date getUpdated_at() {
return updated_at;
}
public void setUpdated_at(Date updated_at) {
this.updated_at = updated_at;
}
public Backlog getBacklog() {
return backlog;
}
public void setBacklog(Backlog backlog) {
this.backlog = backlog;
}
@PrePersist
protected void onCreate() {
this.created_at = new Date();
}
@PreUpdate
protected void onUpdate() {
this.updated_at = new Date();
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.agileintelligence</groupId>
<artifactId>ppmtool</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ppmtool</name>
<description>Personal Project Management Tool</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Solution 1:[1]
you should only put mappedBy once on one side of the relationship. The one that you want to do the "mapping"
in your case maybe remove mappedBy from backlog entity
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | J Asgarov |
