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>