I've created 2 entities in Spring with JPA annotations:
Project:
package com.example.technologyradar.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
#GenericGenerator(name="native", strategy = "native")
private Long id;
private String name;
#ManyToMany(mappedBy = "projects")
private Set<Technology> assignedTechnologies = new HashSet<Technology>();
}
Technology:
package com.example.technologyradar.model;
import com.example.technologyradar.dto.constant.TechnologyStatus;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Technology {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
#GenericGenerator(name="native", strategy = "native")
private Long id;
private String name;
#Enumerated(EnumType.STRING)
private TechnologyStatus technologyStatus;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, targetEntity = Category.class)
#JoinColumn(name="category_id", referencedColumnName = "id", nullable = false)
private Category category;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, targetEntity = Coordinate.class)
#JoinColumn(name="coordinate_id", referencedColumnName = "id", nullable = false)
private Coordinate coordinate;
#ManyToMany
#JoinTable(
name = "projects_technologies",
joinColumns = #JoinColumn(name="technology_id"),
inverseJoinColumns = #JoinColumn(name="project_id")
)
private Set<Project> projects = new HashSet<Project>();
}
My goal is to get List of projects with technologies usage list with ignoring Coordinate and Category from Technology Entity. When I perform simply findAll():
public List<Project> getProjectsWithTechnologyUsage() {
return (List<Project>) projectRepository.findAll();
}
then I'm obtaining famous Infinite Recursion error:
Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: java.util.ArrayList[0]->com.example.technologyradar.model.Project["assignedTechnologies"])]
I know that one of the solutions is to add #JsonManagedReference and #JsonBackRerefence annotations but I don't know how to do it correctly for my particular case.
I would be grateful for any suggestions.
Thanks!
If you use json serialization you can
https://github.com/mikebski/jackson-circular-reference
but anyway add to Project entity
#EqualsAndHashCode(of = "id")
#ToString(of = "id")
Actually, for your scenario, you probably just want #JsonIgnore on top of Technology.projects.
Alternatively, if you sometimes want to print Technology.projects, you can use #JsonView on top of Project.technologies instead, to modify the behavior just for this one scenario where Project is the top level object to serialize.
Related
I am using JPA + Spring Boot for my project. This is the first time I'm using JPA and I'm also very new to Spring Boot.
I want to create two tables file_perms and file_perm_values. I am able to get the definition of file_perms right. However, for my second table file_perm_values, I want to define a composite primary key that consists of the primary key of the file_perms, i.e., id and another String file_id. When I write the definition shown below and use the DDL creation button of Intellij, I get the error Caused by: java.lang.IllegalStateException: The column type is undefined. Table - file_perm_values; Column - file_perm_id
What am I doing wrong?
Could some of the experts out there please help me understand what's the problem and how to fix this?
I'll be very grateful
package com.some.project.persistence.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.time.ZonedDateTime;
import java.util.UUID;
#Entity
#Getter
#Builder
#NoArgsConstructor
#AllArgsConstructor
#ToString(onlyExplicitlyIncluded = true)
#Table(name = "file_perms")
public class FilePermsEntity {
#Id
#GeneratedValue
#Builder.Default
#ToString.Include
#Column(name = "id", nullable = false)
private UUID id = null;
#ToString.Include
#Column(name = "perm_name", nullable = false)
private String permName;
#ToString.Include
#Column(name = "is_active", nullable = false)
private boolean active;
#ToString.Include
#Column(name = "perm_guid")
private String permGuid;
#ToString.Include
#Column(name = "perm_index")
private int permIndex;
#CreatedDate
#Builder.Default
#ToString.Include
#Column(name = "created_at")
private ZonedDateTime createdAt = ZonedDateTime.now();
#Builder.Default
#ToString.Include
#LastModifiedDate
#Column(name = "updated_at")
private ZonedDateTime updatedAt = ZonedDateTime.now();
}
package com.some.project.persistence.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapsId;
import javax.persistence.Table;
import java.io.Serializable;
#Entity
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Builder
#ToString(onlyExplicitlyIncluded = true)
#Table(name = "file_perm_values")
public class FilePermValuesEntity {
#EmbeddedId
#ToString.Include
private FilePermValuesPrimaryKey id;
#ToString.Include
#Column(name = "value")
private String value;
#Getter
#Builder
#Embeddable
#NoArgsConstructor
#AllArgsConstructor
#ToString(onlyExplicitlyIncluded = true)
public static class FilePermValuesPrimaryKey implements Serializable {
private static final long serialVersionUID = 1223232L;
#MapsId
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "file_perm_id", nullable = false)
private FilePermsEntity filePermsEntity;
#ToString.Include
#Column(name = "file_id", nullable = false)
private String fileId;
#Override
public boolean equals(Object o) {
...
}
#Override
public int hashCode() {
...
}
}
}
The code below solved my problem:
#Entity
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Builder
#ToString(onlyExplicitlyIncluded = true)
#Table(name = "file_perm_values")
public class FilePermValuesEntity {
#EmbeddedId
#ToString.Include
private FilePermValuesPrimaryKey id;
#MapsId("filePermId")
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "file_perm_id")
private FilePermsEntity filePermsEntity;
#ToString.Include
#Column(name = "value")
private String value;
#Getter
#Builder
#Embeddable
#NoArgsConstructor
#AllArgsConstructor
#ToString(onlyExplicitlyIncluded = true)
public static class FilePermValuesPrimaryKey implements Serializable {
private static final long serialVersionUID = 1223232L;
#ToString.Include
#Column(name = "file_perm_id", nullable = false)
private UUID filePermId;
#ToString.Include
#Column(name = "file_id", nullable = false)
private String fileId;
#Override
public boolean equals(Object o) {
...
}
#Override
public int hashCode() {
...
}
}
}
I have the following code, where I need to populate a set with multiple objects that are instances of the same class (User). The problem is, I only get the first object when I log.
user = User.builder()
.id(1L)
.username("2397047")
.nickname("test1")
.build();
anotherUser = User.builder()
.id(2L)
.username("23971948")
.nickname("test2")
.build();
Set<User> userSet = new HashSet<>();
userSet.add(user);
userSet.add(anotherUser);
System.out.println("User set from test " + userSet);
This code produces the following output
User set from test [User(id=1, nickname=test1, username= 2397047, password=null, roles=null, groups=null)]
Why am I unable to get the entire collection?
This is my User class
package com.chama.chamaservice.user;
import com.chama.chamaservice.BaseEntity;
import com.chama.chamaservice.Views;
import com.chama.chamaservice.config.ApplicationUserRole;
import com.chama.chamaservice.group.Group;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonView;
import lombok.*;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
#Builder
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#ToString
public class User extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonView(Views.Public.class)
private Long id;
#JsonView(Views.Public.class)
private String nickname;
#JsonView(Views.Public.class)
private String username; // <- Unique user's phone number
private String password;
#ElementCollection(targetClass = ApplicationUserRole.class)
#CollectionTable(name = "user_role", joinColumns = #JoinColumn(name = "user_id"))
#Enumerated(EnumType.STRING)
#Column(name = "role")
private Set<ApplicationUserRole> roles;
#JsonIgnore
#ManyToMany(mappedBy = "groupMembers", fetch = FetchType.LAZY, targetEntity = Group.class)
private Set<Group> groups = new HashSet<>();
}
In the User class, #Data annotation which will implement #Getter, #Setter, #ToString method.
It will print all values in the Set.
Found an answer, although it may not be the optimal solution. I annotated the User class with #EqualsAndHashCode
I know there is so much posts about this and i'm searching for this problem for hours. I assigned the data sources and got rid of other "Cannot resolve column ..." warnings but these 2 warnings just makes no sense because the referencedColumnName method is referencing the same column types in particular classes on the above lines:
Why i'm getting errors on the below 2 lines but not above 2 lines?
CarBrand entity:
package com.sbm.insurance.entities;
import lombok.*;
import javax.persistence.*;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import java.util.List;
#Entity
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Table(
uniqueConstraints = #UniqueConstraint(
name = "carBrand",
columnNames = "carBrand"
)
)
public class CarBrands {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotBlank(message = "Car Brand can't be null or empty")
private String carBrand;
#Min(1)
#Max(999999)
private float carBrandMultiplier;
#OneToMany(
mappedBy = "brand",
cascade = CascadeType.REMOVE,
fetch = FetchType.LAZY
)
private List<Car> car;
}
I would assume because classes Account and Proposal have a field called id, but CarBrands and CarTypes don't.
I have an entity that looks like this:
import lombok.*;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
import javax.persistence.*;
import java.util.List;
import java.util.UUID;
#Entity(name = "EnterpriseGroup")
#Data
#EqualsAndHashCode
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Table(name = "enterprise_groups")
public class EnterpriseGroup {
#Id
#GeneratedValue(generator = "uuid4")
#GenericGenerator(name = "UUID", strategy = "uuid4")
#Type(type = "pg-uuid")
#Column(columnDefinition = "CHAR(36)")
private UUID groupId;
#Column(unique = true)
private String name;
private String description;
#ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST})
#JoinTable(
name = "groups_roles",
joinColumns = {#JoinColumn(name = "groupId")},
inverseJoinColumns = {#JoinColumn(name = "roleId")})
private List<UserRole> roles;
}
I have a default JPA Repository:
import com.fadata.security.domain.entities.EnterpriseGroup;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.UUID;
#Repository
public interface EnterpriseGroupRepository extends JpaRepository<EnterpriseGroup, UUID> {
}
When I try calling repository.findAll() method, I get the following exception:
o.h.engine.jdbc.spi.SqlExceptionHelper: could not extract ResultSet [n/a]
org.postgresql.util.PSQLException: ERROR: operator does not exist: character = uuid
Hint: No operator matches the given name and argument types. You might need to add explicit type casts.
I've tried changing up the UUID type and generation strategies, the column definitions and name, and nothing has worked so far. I tried debugging it by putting a breakpoint on the repository method, but it is never hit, meaning there is some kind of validation that goes on before the method is hit, and that's where this issue originates from. I'm certain I'm passing a valid UUID, because a proper exception is thrown if I pass an invalid UUID format. Yet the exception I get makes me think there is some kind of issue with the way the UUID I pass in with the request is converted and hits the actual app. Any ideas are welcome! Thanks!
Try it UUIDCharType link
#Id
#Type(type = "org.hibernate.type.UUIDCharType")
#GeneratedValue(generator = "UUID")
#GenericGenerator(
name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator"
)
#Column(name = "groupId", updatable = false, nullable = false)
private UUID groupId;
Note: not need generate UUID by UUID.randomUUID()
I am making a Spring web service to learn more about it and I am currently mapping the database. I have a table that has a composite ID, where one of the ID's is a foreign key to another table (ManytoOne).
Creditors
Creditor_Invoices
ID
Creditor_ID
name
Invoice_ID
As anywhere you buy something they use their own way of making ID's it has a composite ID like this.
My Current code:
Serializable class CInvoiceId:
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import java.io.Serializable;
import java.util.Objects;
#Embeddable
public class CInvoiceId implements Serializable {
#ManyToOne
#JoinColumn(name = "creditors_id", nullable = false)
private Creditor cInvoiceCreditorId;
#Column(name = "invoice_id", nullable = false)
private String cInvoiceId;
public CInvoiceId(Creditor creditor, String cInvoiceId){
this.cInvoiceCreditorId = creditor;
this.cInvoiceId = cInvoiceId;
}
//Setters, Getters, Equals and Hash
}
My Creditor class
import javax.persistence.*;
import java.util.List;
#Entity
#Table(name = "creditors")
public class Creditor {
#Id
#GeneratedValue
#Column(name = "id")
private int creditorId;
#Column(name = "name",nullable = false)
private String creditorName;
#OneToMany(mappedBy = "cInvoiceCreditorId")
private List<CInvoice> cInvoices;
}
My CInvoice class:
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;
#Entity
#Table(name = "c_invoices")
public class CInvoice {
#EmbeddedId
private CInvoiceId cInvoiceID;
}
When I start it to try and test it I get the error that it can not find the mapped by from the creditor class, but I don't know what I should map it to as the ID is now made in the CInvoiceId class. What should it be?
Regards
Dany
You can use "derived identities" to map these classes:
Creditor:
#Entity
#Table(name = "creditors")
public class Creditor {
#Id
#GeneratedValue
#Column(name = "id")
private int id;
#Column(name = "name",nullable = false)
private String name;
#OneToMany(mappedBy = "creditor")
private List<CInvoice> invoices;
}
CInvoiceId:
#Embeddable
public class CInvoiceId implements Serializable {
#Column(name = "invoice_id", nullable = false)
private String invoiceID;
private int creditorID; // corresponds to PK type of Creditor
// ...
}
CInvoice:
#Entity
#Table(name = "c_invoices")
public class CInvoice {
#EmbeddedId
private CInvoiceId id;
#MapsId("creditorID") // maps creditorID attribute of embedded id
#ManyToOne
#JoinColumn(name = "creditors_id", nullable = false)
Creditor creditor;
}
Derived identities are discussed (with examples) in the JPA 2.2 spec in section 2.4.1.