Get Jackson to ignore some fields at controller level in Spring Boot - spring-boot

I have the following class:
#Entity
#Table(name = "Positions")
#NamedQuery(name = "Position.findAll", query = "SELECT p FROM Position p")
public class Position implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "id")
private Long id;
private String title;
private String description;
#ElementCollection
#CollectionTable(name = "qualifications", joinColumns = #JoinColumn(name = "position_id"))
#Column(name = "required_qualifications")
private List<String> requiredQualifications;
#ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
#JoinTable(name = "positions_competencies", joinColumns = #JoinColumn(name = "position_id"), inverseJoinColumns = #JoinColumn(name = "Competence_id"))
private List<Competence> competencies;
#ManyToOne
#JoinColumn(name = "department_id")
private Department department;
I'm using spring boot with spring data.
I want to ignore some of the fields in the getAllPositions method, but not in the getPositionById method, so #JsonIgnore won't work for me. What is the best way to do this in Spring Boot 2.0.2?
Here is the controller:
#Autowired
private PositionRepository positionRepository;
#GetMapping(path = "/positions")
public Iterable<Position> getAllPositions() {
return positionRepository.findAll();
}
#GetMapping(path = "/positions/{id}")
public Position getPositionById(#PathVariable Long id) {
return positionRepository.findById(id).get();
}

Related

(Do not display relationship values)

I have two entity with name of the article and article Category.
and they have one-to-many relationships.
I use #JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class,property = "id")
but I cant see data of article category(category_id) in spring data rest.
ArticleCategory.class
#Entity
#Table(name = "article_category")
#Getter
#Setter
public class ArticleCategory implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "category_name")
private String categoryName;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "articleCategory", fetch = FetchType.LAZY)
private Set<Article> articles = new HashSet<>();
}
Article.class
#Entity
#Table(name = "article")
#Getter
#Setter
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Article implements Serializable {
public Article() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "category_id", nullable = false)
private ArticleCategory articleCategory;
#Column(name = "title")
private String title;
#Column(name = "image_url")
private String image_url;
#Column(name = "short_description")
private String short_description;
#Column(name = "text")
private String text;
#Column(name = "keywords", nullable = true)
private String keywords;
#Column(name = "visit", nullable = false)
private int visit;
#Column(name = "code", nullable = false)
private UUID code;
#Column(name = "date_created")
#CreationTimestamp
private Date dateCreated;
#Column(name = "date_updated", nullable = false)
#UpdateTimestamp
private Date dateUpdated;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private User user;
public Article(String title, String image_url, String short_description, String text, String keywords, int visit, UUID code) {
this.title = title;
this.image_url = image_url;
this.short_description = short_description;
this.text = text;
this.keywords = keywords;
this.visit = visit;
this.code = code;
}
}
Article Repository
#CrossOrigin("http://localhost:4200")
#RepositoryRestResource(collectionResourceRel = "article", path = "article")
public interface ArticleRepository extends JpaRepository<Article,Long> {
Article findByCode(UUID uuid);
}
And this is output of spring data rest
enter image description here
That is exactly because you used #JsonManagedReference and #JsonBackReference. Keep in mind the following when using them:
#JsonManagedReference is the forward part of the relationship and is the one that gets serialized normally.
#JsonBackReference is the back part of the relationship and it will be omitted from serialization.
The serialized Article object does not contain a reference to the ArticleCategory object.
If you want to have any ArticleCategory data when serializing Article you can either use #JsonIdentityInfo so that one of the properties is serialized (in this case I've chosen id for both):
#Entity
#Table(name = "article")
#Getter
#Setter
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Article implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "category_id", nullable = false)
private ArticleCategory articleCategory;
}
#Entity
#Table(name = "article_category")
#Getter
#Setter
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class ArticleCategory implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "category_name")
private String categoryName;
#OneToMany(cascade = CascadeType.ALL,mappedBy = "articleCategory" ,fetch = FetchType.LAZY)
private Set<Article> articles=new HashSet<>();
}
If you are only interested in categoryId another possibility would be to use #JsonIgnore on private Set<Article> articles property so that it is not serialized:
#Entity
#Table(name = "article_category")
#Getter
#Setter
public class ArticleCategory implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "category_name")
private String categoryName;
#JsonIgnore
#OneToMany(cascade = CascadeType.ALL,mappedBy = "articleCategory" ,fetch = FetchType.LAZY)
private Set<Article> articles=new HashSet<>();
}
If none of those suits your needs you might need to implement your own custom serializer. You can read more about all those options at https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion.
I solved the problem using the controller
And that's why #JsonManageRefrence and #JsonBackRefrence do not work
I replaced the lazy load with the eager load in both entity
#ManyToOne(fetch = FetchType.Eager)
#JoinColumn(name = "user_id")
#JsonManageRefrence
private User user;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "articleCategory",
fetch = FetchType.Eager)
#JsonBackRefrence
private Set<Article> articles = new HashSet<>();
and then add a controller
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
#RequestMapping("/getAllArticle")
public class MyController {
private ArticleRepository articleRepository;
// you must do constructor injection
#GetMapping("/getAllArticle")
public List<Article> allArticle()
{
return articleRepository.findAll();
}
}

#Putmapping in SpringBoot delete relationship Object

I am using #Putmapping to update an object. When I look at the logs it has deleted a relationship. I don't know why, but I need help to understand. My code is below.
I have an object Employee, which has a relationship with Project. I am updating an Employee, but it deletes record from the relationship table.
#PutMapping(path = "/{id}", consumes="application/json")
#ResponseStatus(HttpStatus.OK)
public Employee update(#RequestBody Employee emp) {
return empService.save(emp);
}
#Entity
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "employee_seq")
#SequenceGenerator(name = "employee_seq", sequenceName = "employee_seq",
allocationSize = 1,initialValue=1)
private long employeeId;
private String firstName;
private String lastName;
private String email;
#ManyToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST},
fetch = FetchType.LAZY)
#JoinTable(name = "project_employee", joinColumns = #JoinColumn(name="employee_id"),
inverseJoinColumns = #JoinColumn(name="project_id"))
#JsonIgnore
private List<Project> projects;
public Employee() {
}
}
#Entity
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "project_seq")
#SequenceGenerator(name = "project_seq", sequenceName = "project_seq",
allocationSize = 1,initialValue=1)
private long projectId;
private String name;
private String stage; //NONSTARTED, COMPLETED, INPROGRESS
private String description;
#ManyToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST},
fetch = FetchType.LAZY)
#JoinTable(name = "project_employee", joinColumns = #JoinColumn(name="project_id"),
inverseJoinColumns = #JoinColumn(name="employee_id"))
#JsonIgnore
private List<Employee> empList;
public Project() {
}
}

How to map an entity as java.util.Map with spring Data JPA?

I have such entities:
Bonus_Request entity:
#Entity
#Table(name = "bonus_request")
public class BonusRequest {
//some code above...
#OneToMany(fetch = FetchType.EAGER, mappedBy = "bonusRequest")
#JsonManagedReference(value = "parameter-bonus_request")
private Set<BonusRequestParameter> parameters;
}
Bonus_Request_Parameter entity:
#Entity
#Table(name = "bonus_request_parameter")
public class BonusRequestParameter {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Size(max = 30)
#Column(name = "parameter", nullable = false)
private String parameter;
#Size(max = 50)
#Column(name = "value", nullable = false)
private String value;
#JoinColumn(name = "bonus_request_id", nullable = false)
#ManyToOne(fetch = FetchType.LAZY)
#JsonBackReference(value = "parameter-bonus_request")
private BonusRequest bonusRequest;
}
I wonder if it is possible to map the BonusRequestParameter entity as a java.util.Map field in the BonusRequest entity.
For example:
#Entity
#Table(name = "bonus_request")
public class BonusRequest {
#OneToMany(fetch = FetchType.EAGER, mappedBy = "bonusRequest")
private Map<String, String> parameters; //String parameter, String value
}
I use:
Spring Data JPA - 2.1.7
PostgreSQL DB - 10.7
This will work. It loads the map eagerly by default.
#Entity
#Table(name = "bonus_request")
public class BonusRequest {
...
#ElementCollection
private Map<String, String> parameters; //String parameter, String value
}
Resolved with this:
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "bonus_request_parameter",
joinColumns = {#JoinColumn(name = "bonus_request_id", referencedColumnName = "id")})
#MapKeyColumn(name = "parameter")
#Column(name = "value")
private Map<String, String> parameters;
Thank you for help.

Spring JpaRepository manyToMany bidirectional should save instead of update

if got a language table and a system table with a many-to-many relationship:
Language:
#JsonAutoDetect
#Entity
#Table(name = "language")
public class Language implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "language_id", nullable = false)
private int languageId;
#Column(name = "language_name", nullable = false)
private String languageName;
#Column(name = "language_isocode", nullable = false)
private String languageIsoCode;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "system_language", joinColumns = {#JoinColumn(name = "language_id", updatable = false)},
inverseJoinColumns = {
#JoinColumn(name = "system_id", updatable = false)}, uniqueConstraints = {
#UniqueConstraint(columnNames = {
"language_id",
"system_id"
})})
private List<System> systems;
public Language() {
}
// GETTER & SETTERS
// ....
}
System
#JsonAutoDetect
#Entity
#Table(name = "system")
public class System implements Serializable {
#Id
#Column(name = "system_id", nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer systemId;
#Column(name = "system_name", nullable = false, unique = true)
private String systemName;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "university_id", nullable = false)
private University university;
#JoinColumn(name = "calender_id", nullable = false)
#OneToOne(fetch = FetchType.EAGER)
private Calendar calender;
#OneToMany(mappedBy = "system")
#LazyCollection(LazyCollectionOption.FALSE)
private List<SystemUserRole> systemUserRoleList;
#OneToMany(mappedBy = "system")
#LazyCollection(LazyCollectionOption.FALSE)
private List<Role> roleList;
#OneToOne(mappedBy = "system")
#LazyCollection(LazyCollectionOption.FALSE)
private CsmUserEntity csmUserEntity;
#ManyToMany(mappedBy = "systems")
#LazyCollection(LazyCollectionOption.FALSE)
private List<Language> languages;
public System() {
}
// GETTER & SETTERS
// ....
}
When im writing a first dataset (systemId=1, language_id=20) into the table, everything works fine. But when i try to write a second dataset with the same language_id but with other system_id (systemId=2, language_id=20), then the existing dataset gets updated. But i want to have a new dataset instead. What can i do?
Thanks in advance!

Customizing HATEOS URI

I have a Spring Boot Data Rest project I'm working on.
Specifically, I have the following dependencies:
dependencies {
compile 'org.springframework.boot:spring-boot-starter-data-jpa:1.1.9.RELEASE'
compile 'org.springframework.boot:spring-boot-starter-data-rest:1.1.9.RELEASE'
compile 'org.springframework.boot:spring-boot-starter-actuator:1.1.9.RELEASE'
}
I have three entities:
#Entity
#Table(name = "prefecture", uniqueConstraints={#UniqueConstraint(columnNames = {"code", "name"})})
public class Prefecture implements Serializable {
private static final long serialVersionUID = -4664664252005282494L;
#Id
#Column(name = "code")
private Integer code;
#Column(name = "name")
private String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "prefecture")
private List<City> cities;
...
#Entity
#Table(name = "city", uniqueConstraints = {#UniqueConstraint(columnNames = {"code", "name"})})
public class City implements Serializable {
private static final long serialVersionUID = 1077260811602686775L;
#Id
#Column(name = "code")
private Integer code;
#ManyToOne
#JoinColumn(name = "prefecture_code", referencedColumnName = "code")
private Prefecture prefecture;
#Column(name = "name", unique = true)
private String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "city")
private List<TownArea> townAreas;
...
#Entity
#Table(name = "town_area", uniqueConstraints={#UniqueConstraint(columnNames = {"name"})})
public class TownArea implements Serializable {
private static final long serialVersionUID = -4908446167092081914L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "name")
private String name;
#ManyToOne
#JoinColumn(name = "city_code", referencedColumnName = "code")
private City city;
#Column(name = "prefecture_code")
private Integer prefectureCode;
#Column(name = "postal_code")
private String postalCode;
...
And three repositories:
#RepositoryRestResource(collectionResourceRel = "cities", path = "cities")
public interface CityRepository extends PagingAndSortingRepository<City, Integer> {}
#RepositoryRestResource(collectionResourceRel = "prefectures", path = "prefectures")
public interface PrefectureRepository extends PagingAndSortingRepository<Prefecture, Integer> {}
#RepositoryRestResource(collectionResourceRel = "town_areas", path = "town_areas")
public interface TownAreaRepository extends PagingAndSortingRepository<TownArea, Integer> {}
Given this, when I run my application locally I have a set of URLs like this:
http://localhost:8080/prefectures
http://localhost:8080/prefectures/1
http://localhost:8080/prefectures/1/cities
http://localhost:8080/cities/2/townareas
http://localhost:8080/townareas/3
However, I would like to configure the following URLs:
http://localhost:8080/prefectures/1/cities/2/
http://localhost:8080/prefectures/1/cities/2/townareas
http://localhost:8080/prefectures/1/cities/2/townareas/3
Is there a way I can customize the uris to accomplish this?

Resources