POSTing oneToMany in a REST call via Spring Boot API - java

I have a problem when I POST from a single REST call to create a Library and associate Books for the library. The library record is created, but the associated books are not. Library and Book has oneToMany relationship.
My POST request and response is as below -
POST - http://localhost:8080/libraries/
REQUEST BODY
{
"name":"My Library",
"books": [
{"title": "Effective Java", "isbn": "1234"},
{"title": "Head First Java", "isbn": "5678"}
]
}
REPOSNSE
1
GET Libraries after POST - http://localhost:8080/libraries/
[
{
"id": 1,
"name": "My Library",
"books": [],
"address": null
}
]
POST to create Library and add Books
GET REQUEST for Libraries
MODELs
package com.publiclibrary.domain;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import org.springframework.data.rest.core.annotation.RestResource;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#NoArgsConstructor
#Entity
public class Library {
#Id
#GeneratedValue
private long id;
#Column
private String name;
#OneToMany(mappedBy = "library")
private List<Book> books;
#OneToOne
#JoinColumn(name = "address_id")
#RestResource(path = "libraryAddress", rel="address")
private Address address;
// standard constructor, getters, setters
public Library(String name) {
super();
this.name = name;
}
}
package com.publiclibrary.domain;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#NoArgsConstructor
//#Builder
//#AllArgsConstructor
#Entity
public class Book {
#Id
#GeneratedValue
private long id;
#NotNull
private String title, isbn;
#ManyToOne
#JoinColumn(name="library_id")
private Library library;
#ManyToMany(mappedBy = "books")
private List<Author> authors;
}
REPOSITORY
package com.publiclibrary.repo;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import com.publiclibrary.domain.Book;
#RepositoryRestResource(path = "books", collectionResourceRel = "books")
public interface BookRepository extends PagingAndSortingRepository<Book, Long> {
}
package com.publiclibrary.repo;
import org.springframework.data.repository.CrudRepository;
import com.publiclibrary.domain.Library;
public interface LibraryRepository extends CrudRepository<Library, Long> {
}
Service
package com.publiclibrary.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.publiclibrary.domain.Library;
import com.publiclibrary.repo.LibraryRepository;
#Service
public class LibraryService {
#Autowired
LibraryRepository libraryRepository;
public List<Library> getAllLibrarys() {
List<Library> librarys = new ArrayList<Library>();
libraryRepository.findAll().forEach(library -> librarys.add(library));
return librarys;
}
public Library getLibraryById(long id) {
return libraryRepository.findById(id).get();
}
public void saveOrUpdate(Library library) {
libraryRepository.save(library);
}
public void delete(long id) {
libraryRepository.deleteById(id);
}
}
RESTCONTROLLER
package com.publiclibrary.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.publiclibrary.domain.Library;
import com.publiclibrary.service.LibraryService;
#RestController
public class LibraryController {
#Autowired
LibraryService libraryService;
#GetMapping("/libraries")
private List<Library> getAllLibrarys() {
return libraryService.getAllLibrarys();
}
#GetMapping("/libraries/{id}")
private Library getLibrary(#PathVariable("id") int id) {
return libraryService.getLibraryById(id);
}
#DeleteMapping("/libraries/{id}")
private void deleteLibrary(#PathVariable("id") int id) {
libraryService.delete(id);
}
#PostMapping("/libraries")
private long saveLibrary(#RequestBody Library library) {
libraryService.saveOrUpdate(library);
return library.getId();
}
}
How can I create a Library and add Books as I intend? Appreciate any help!

Try adding cascade persist (or better just cascade all) on books collection in Library class. E.g.
#OneToMany(fetch = FetchType.LAZY, mappedBy = "library", cascade = CascadeType.ALL)
private List<Book> books;

I followed this article and resolved the problem. I explicitly handled parsing the JSON and creating my data objects. Additionally, I added add and remove methods in parent (Library) class and defined the equals and hashcode for reasons explained in the link above.
My code changes as below -
Library -
#OneToMany(mappedBy = "library", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonIgnoreProperties("library")
private List<Book> books = new ArrayList<>();
public void addBook(Book book) {
books.add(book);
book.setLibrary(this);
}
public void removeBook(Book book) {
books.remove(book);
book.setLibrary(null);
}
Book -
#JsonIgnoreProperties("books")
private Library library;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Book )) return false;
return id != null && id.equals(((Book) o).id);
}
#Override
public int hashCode() {
return 31;
}
LibraryController -
#PostMapping("/libraries")
private long saveLibrary(#RequestBody Map<String, Object> payload) {
Library library = new Library();
library.setName(payload.get("name").toString());
#SuppressWarnings("unchecked")
List<Map<String, Object>> books = (List<Map<String, Object>>) payload.get("books");
for (Map<String, Object> bookObj : books) {
Book book = new Book();
book.setTitle(bookObj.get("title").toString());
book.setIsbn(bookObj.get("isbn").toString());
library.addBook(book);
}
libraryService.saveOrUpdate(library);
return library.getId();
}

Related

How i can duplicate a record with your dependents in spring boot

In my use case I need to create an endpoint that duplicates a record and its dependents by copying the data from the current record to a new record creating new primary keys.
Current response: Original record
[
{
"id": 1,
"name": "Grandparent One",
"parents": [
{
"id": 1,
"name": "Parent One",
"children": [
{
"id": 1,
"name": "Child One"
},
{
"id": 2,
"name": "Child Two"
}
]
}
]
}
]
Expected response: Original record and Duplicate record
[
{
"id": 1,
"name": "Grandparent One",
"parents": [
{
"id": 1,
"name": "Parent One",
"children": [
{
"id": 1,
"name": "Child One"
},
{
"id": 2,
"name": "Child Two"
}
]
}
]
},
{
"id": 2,
"name": "Grandparent One Copy",
"parents": [
{
"id": 2,
"name": "Parent One",
"children": [
{
"id": 3,
"name": "Child One"
},
{
"id": 4,
"name": "Child Two"
}
]
}
]
}
]
Can anyone give me a hint on how to do the implementation this endpoint in the GrandparentController?
#PostMapping("{id}/duplicate")
public ResponseEntity<Grandparent> duplicate(#NonNull #PathVariable long id) {
//How to implement this endpoint?
return null;
}
My classes:
MODELS
Grandparent
package com.example.demo.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
#Entity
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "grandparents")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Grandparent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
Parent
package com.example.demo.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
#Entity
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "parents")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Parent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "grandparent_id", nullable = false
, foreignKey = #ForeignKey(name = "fk_parents_grandparent1"))
private Grandparent grandparent;
private String name;
}
Children
package com.example.demo.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
#Entity
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "children")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Children {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "parent_id", nullable = false
, foreignKey = #ForeignKey(name = "fk_children_parent1"))
private Parent parent;
private String name;
}
DTOs
GrandparentPost
package com.example.demo.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class GrandparentPost {
private String name;
}
ParentPost
package com.example.demo.dto;
import com.example.demo.model.Grandparent;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class ParentPost {
private Grandparent grandparent;
private String name;
}
ChildrenPost
package com.example.demo.dto;
import com.example.demo.model.Parent;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class ChildrenPost {
private Parent parent;
private String name;
}
GrandparentResponseDto
package com.example.demo.dto;
import com.example.demo.model.Grandparent;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
#Data
#NoArgsConstructor
public class GrandparentResponseDto {
private Long id;
private String name;
private List<ParentResponseDto> parents;
public GrandparentResponseDto(Grandparent grandparent) {
this.id = grandparent.getId();
this.name = grandparent.getName();
}
}
ParentResponseDto
package com.example.demo.dto;
import com.example.demo.model.Parent;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
#Data
#NoArgsConstructor
public class ParentResponseDto {
private Long id;
private String name;
private List<ChildrenResponseDto> children;
public ParentResponseDto(Parent parent) {
this.id = parent.getId();
this.name = parent.getName();
}
}
ChildrenResponseDto
package com.example.demo.dto;
import com.example.demo.model.Children;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#NoArgsConstructor
public class ChildrenResponseDto {
private Long id;
private String name;
public ChildrenResponseDto(Children children) {
this.id = children.getId();
this.name = children.getName();
}
}
MAPPERS
GrandparentMapper
package com.example.demo.mapper;
import com.example.demo.dto.GrandparentPost;
import com.example.demo.model.Grandparent;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
#Mapper(componentModel = "spring")
public abstract class GrandparentMapper {
public static final GrandparentMapper INSTANCE = Mappers.getMapper(GrandparentMapper.class);
public abstract Grandparent toGrandparent(GrandparentPost grandparentPost);
}
ParentMapper
package com.example.demo.mapper;
import com.example.demo.dto.ParentPost;
import com.example.demo.model.Parent;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
#Mapper(componentModel = "spring")
public abstract class ParentMapper {
public static final ParentMapper INSTANCE = Mappers.getMapper(ParentMapper.class);
public abstract Parent toParent(ParentPost parentPost);
}
ChildrenMapper
package com.example.demo.mapper;
import com.example.demo.dto.ChildrenPost;
import com.example.demo.model.Children;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
#Mapper(componentModel = "spring")
public abstract class ChildrenMapper {
public static final ChildrenMapper INSTANCE = Mappers.getMapper(ChildrenMapper.class);
public abstract Children toChildren(ChildrenPost childrenPost);
}
REPOSITORIES
GrandparentRep
package com.example.demo.repository;
import com.example.demo.model.Grandparent;
import org.springframework.data.jpa.repository.JpaRepository;
public interface GrandparentRep extends JpaRepository<Grandparent, Long> {
}
ParentRep
package com.example.demo.repository;
import com.example.demo.model.Parent;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ParentRep extends JpaRepository<Parent, Long> {
List<Parent> findByGrandparent_Id(long grandparent);
}
ChildrenRep
package com.example.demo.repository;
import com.example.demo.model.Children;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ChildrenRep extends JpaRepository<Children, Long> {
List<Children> findByParent_Id(long parent);
}
SERVICES
GrandparentService
package com.example.demo.service;
import com.example.demo.dto.GrandparentPost;
import com.example.demo.mapper.GrandparentMapper;
import com.example.demo.model.Grandparent;
import com.example.demo.repository.GrandparentRep;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
#Service
#RequiredArgsConstructor
public class GrandparentService {
private final GrandparentRep grandparentRep;
public List<Grandparent> findAll() {
return grandparentRep.findAll();
}
public Optional<Grandparent> findById(long id) {
return grandparentRep.findById(id);
}
#Transactional
public Grandparent save(GrandparentPost grandparentPost) {
return grandparentRep.save(GrandparentMapper.INSTANCE.toGrandparent(grandparentPost));
}
}
ParentService
package com.example.demo.service;
import com.example.demo.dto.ParentPost;
import com.example.demo.mapper.ParentMapper;
import com.example.demo.model.Parent;
import com.example.demo.repository.ParentRep;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
#Service
#RequiredArgsConstructor
public class ParentService {
private final ParentRep parentRep;
public List<Parent> findBy(long grandparent) {
return parentRep.findByGrandparent_Id(grandparent);
}
#Transactional
public Parent save(ParentPost parentPost) {
return parentRep.save(ParentMapper.INSTANCE.toParent(parentPost));
}
}
ChildrenService
package com.example.demo.service;
import com.example.demo.dto.ChildrenPost;
import com.example.demo.mapper.ChildrenMapper;
import com.example.demo.model.Children;
import com.example.demo.model.Parent;
import com.example.demo.repository.ChildrenRep;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
#Service
#RequiredArgsConstructor
public class ChildrenService {
private final ChildrenRep childrenRep;
public List<Children> findBy(long parent) {
return childrenRep.findByParent_Id(parent);
}
#Transactional
public Children save(ChildrenPost childrenPost) {
return childrenRep.save(ChildrenMapper.INSTANCE.toChildren(childrenPost));
}
}
CONTROLLERS
GrandparentController
package com.example.demo.controller;
import com.example.demo.dto.ChildrenResponseDto;
import com.example.demo.dto.GrandparentPost;
import com.example.demo.dto.GrandparentResponseDto;
import com.example.demo.dto.ParentResponseDto;
import com.example.demo.model.Grandparent;
import com.example.demo.service.ChildrenService;
import com.example.demo.service.GrandparentService;
import com.example.demo.service.ParentService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.NonNull;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
#RestController
#RequestMapping("api/v1/grandparents")
#RequiredArgsConstructor
public class GrandparentController {
private final GrandparentService grandparentService;
private final ParentService parentService;
private final ChildrenService childrenService;
#GetMapping
public ResponseEntity<List<Grandparent>> findAll() {
return ResponseEntity.ok(grandparentService.findAll());
}
#GetMapping("/{id}")
public ResponseEntity<Optional<Grandparent>> findById(#NonNull #PathVariable long id) {
return ResponseEntity.ok(grandparentService.findById(id));
}
#GetMapping("/{id}/stats")
public ResponseEntity<List<GrandparentResponseDto>> findByStats (#NonNull #PathVariable long id) {
var grandparentStatsDto = grandparentService.findById(id)
.stream()
.map(GrandparentResponseDto::new)
.collect(Collectors.toList());
//List parents
grandparentStatsDto.forEach(grandparentStatsList -> {
List<ParentResponseDto> parentResponseDto = parentService
.findBy(grandparentStatsList.getId())
.stream().map(ParentResponseDto::new)
.collect(Collectors.toList());
//List children
parentResponseDto.forEach(parentStatsList -> {
List<ChildrenResponseDto> childrenResponseDto = childrenService
.findBy(parentStatsList.getId())
.stream().map(ChildrenResponseDto::new)
.collect(Collectors.toList());
parentStatsList.setChildren(childrenResponseDto);
});
grandparentStatsList.setParents(parentResponseDto);
});
return ResponseEntity.ok(grandparentStatsDto);
}
#PostMapping
public ResponseEntity<Grandparent> save(#NonNull #Valid #RequestBody GrandparentPost grandparentPost) {
return new ResponseEntity<>(grandparentService.save(grandparentPost), HttpStatus.CREATED);
}
#PostMapping("{id}/duplicate")
public ResponseEntity<Grandparent> duplicate(#NonNull #PathVariable long id) {
//How to implement this endpoint?
return null;
}
}
ParentController
package com.example.demo.controller;
import com.example.demo.dto.ParentPost;
import com.example.demo.model.Grandparent;
import com.example.demo.model.Parent;
import com.example.demo.service.ParentService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.NonNull;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
#RestController
#RequestMapping("api/v1/grandparents/{grandparent}/parents")
#RequiredArgsConstructor
public class ParentController {
private final ParentService parentService;
#GetMapping
public ResponseEntity<List<Parent>> findBy(#PathVariable long grandparent) {
return ResponseEntity.ok(parentService.findBy(grandparent));
}
#PostMapping
public ResponseEntity<Parent> save(#NonNull #Valid #RequestBody ParentPost parentPost
, #NonNull #PathVariable long grandparent) {
parentPost.setGrandparent(new Grandparent(grandparent, null));
return new ResponseEntity<>(parentService.save(parentPost), HttpStatus.CREATED);
}
}
ChildrenController
package com.example.demo.controller;
import com.example.demo.dto.ChildrenPost;
import com.example.demo.model.Children;
import com.example.demo.model.Parent;
import com.example.demo.service.ChildrenService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.NonNull;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
#RestController
#RequestMapping("api/v1/grandparents/{grandparent}/parents/{parent}/children")
#RequiredArgsConstructor
public class ChildrenController {
private final ChildrenService childrenService;
#GetMapping
public ResponseEntity<List<Children>> findBy(#PathVariable long grandparent) {
return ResponseEntity.ok(childrenService.findBy(grandparent));
}
#PostMapping
public ResponseEntity<Children> save(#NonNull #Valid #RequestBody ChildrenPost childrenPost
, #NonNull #PathVariable long parent) {
childrenPost.setParent(new Parent(parent, null, null));
return new ResponseEntity<>(childrenService.save(childrenPost), HttpStatus.CREATED);
}
}
I solved it like this:
#PostMapping("{id}/duplicate")
public ResponseEntity<Grandparent> duplicate(#NonNull #PathVariable long id) {
var originGrandparent = grandparentService.findById(id);
var originParentList = parentService.findBy(originGrandparent.get().getId());
var originChildrenList = new ArrayList<Children>();
originParentList.forEach(originParent -> {
List<Children> originChildren = childrenService.findBy(originParent.getId());
originChildrenList.addAll(originChildren);
});
var newGrandparent = new GrandparentPost();
newGrandparent.setName(originGrandparent.get().getName() + " copy");
var savedGrandparent = grandparentService.save(newGrandparent);
var newParent = new ParentPost();
var savedParentList = new ArrayList<Parent>();
originParentList.forEach(originParent -> {
newParent.setGrandparent(new Grandparent(savedGrandparent.getId(), null));
newParent.setName(originParent.getName());
var savedParent = parentService.save(newParent);
savedParentList.add(savedParent);
originChildrenList.forEach(origenChild -> {
if (Objects.equals(origenChild.getParent().getId(), originParent.getId())) {
var newChild = new ChildrenPost();
newChild.setParent(savedParent);
newChild.setName(origenChild.getName());
childrenService.save(newChild);
}
});
});
return ResponseEntity.ok(savedGrandparent);
}
If anyone knows a way to improve this code, feel free to share.

Is there a way to make spring boot mongodb not changing your id attribute value to his object_id?

I am working in a project to learn spring boot, i have a problem where i have a attribute actor_id stored in mongodb with a value x but when i do mongoRepository.findall(), he changes the value of my actor_id to the value of the object_id generated automatically by mongodb, so even if i want to find a value by id i have to put the object_id value instead of the value of actor_id stored in database. Image below to better help understand.
I wanted that the returned value of a get http://localhost:8093/actors in actor_id be = 1 instead of 61634ad37e775d4b87635129.
Below is my code.
Actor.java:
package com.film.SpringAplication.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
#Document(collection="actor")
#AllArgsConstructor
#Data
public class Actor {
#Id
String actor_id;
String first_name;
String last_name;
}
ActorController.java
package com.film.SpringAplication.controller;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.film.SpringAplication.model.Actor;
import com.film.SpringAplication.service.ActorService;
#RestController
#RequestMapping("/actors")
public class ActorController {
#Autowired
ActorService actorService;
#PostMapping
public String addActor(#RequestBody Actor actor) {
return actorService.addActor(actor);
}
#GetMapping
public List<Actor> getActors() {
return actorService.getActors();
}
#GetMapping("/{id}")
public List<Actor> getActor(#PathVariable String id) {
return actorService.getActor(id);
}
#DeleteMapping("/{id}")
public String deleteActor(#PathVariable String id) {
return actorService.deleteActor(id);
}
}
ActorService.java:
package com.film.SpringAplication.service;
import java.util.List;
import java.util.Optional;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import com.film.SpringAplication.model.Actor;
import com.film.SpringAplication.repository.ActorRepository;
import lombok.RequiredArgsConstructor;
#Service
#RequiredArgsConstructor
public class ActorService {
private final ActorRepository actorRepository;
private final MongoTemplate mongoTemplate;
public String addActor(Actor actor) {
actorRepository.save(actor);
return "Actor Added";
}
public List<Actor> getActors() {
List<Actor> lista = actorRepository.findAll();
return lista;
}
public List<Actor> getActor(String id) {
Query query=new Query()
.addCriteria(Criteria.where("actor_id").is(id));
return mongoTemplate.find(query,Actor.class);
//return actorRepository.findById(id);
}
public String deleteActor(String id) {
actorRepository.deleteById(id);
return "User deleted";
}
}
ActorRepository.java:
package com.film.SpringAplication.repository;
import org.springframework.data.mongodb.repository.MongoRepository;
import com.film.SpringAplication.model.Actor;
public interface ActorRepository extends MongoRepository<Actor,String>{
}
What you can do is, you can use #Field. You annotate #Id to actor_id. So basically it takes as the default primary key. You can do two things. You can annotate _id as default primary key.
#Document(collection="actor")
#AllArgsConstructor
#Data
public class Actor {
#Id
ObjectId _id;
String actor_id;
String first_name;
String last_name;
}
Else you can annotate #Field
#Document(collection="actor")
#AllArgsConstructor
#Data
public class Actor {
#Id
#Field("actor_id")
String actor_id;
String first_name;
String last_name;
}
Related answer

I Am Facing "java.lang.IllegalArgumentException: Can not set int field com.example.demo.model.Customer.customerId to java.util.LinkedHashMap"

I am getting:
java.lang.IllegalArgumentException: Can not set int field com.example.demo.model.Customer.customerId to java.util.LinkedHashMap
in my Spring Boot Project in which I am trying to persist data of two Pojo classes using Hibernate One-To-Many Relationship. I am trying to save values of a persistent class that has a Collection element Set defined.
The Parent Pojo Class:-
package com.example.demo.model;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name = "vendor")
public class Vendor {
#Id
int vendorId;
#Column
String vendorName;
#OneToMany(fetch = FetchType.LAZY, targetEntity = Customer.class, cascade = CascadeType.ALL)
#JoinColumn(name = "vendorId")
Set children;
public int getVendorId() {
return vendorId;
}
public void setVendorId(int vendorId) {
this.vendorId = vendorId;
}
public String getVendorName() {
return vendorName;
}
public void setVendorName(String vendorName) {
this.vendorName = vendorName;
}
public Set getChildren() {
return children;
}
public void setChildren(Set children) {
this.children = children;
}
}
Child Pojo Class:-
package com.example.demo.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GeneratorType;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
#Entity
#Table(name = "customer")
public class Customer {
#Id
int customerId;
#Column
String customerName;
public int getCustomerId() {
return customerId;
}
public void setCustomerId(int customerId) {
this.customerId = customerId;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
}
Controller Class:-
package com.example.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.model.Vendor;
import com.example.demo.service.VendorDataSaveService;
#RestController
public class VendorSaveController {
#Autowired
private VendorDataSaveService dataSaveService;
#PostMapping("/save")
public void saveVendor(#RequestBody Vendor vendor) {
dataSaveService.saveVendorRecord(vendor);
}
}
Service Class:-
package com.example.demo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.demo.model.Vendor;
import com.example.demo.repository.VendorDataSaveRepository;
#Service
public class VendorDataSaveService {
#Autowired
private VendorDataSaveRepository repository;
public void saveVendorRecord(Vendor vendor) {
repository.save(vendor);
}
}
Repository Class:-
package com.example.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.demo.model.Vendor;
public interface VendorDataSaveRepository extends JpaRepository<Vendor, Integer> {
}
The JSON Format which I am sending from Postman:-
{
"vendorId" : 101,
"vendorName" : "JAIN BOOKS",
"children" : [{
"customerId" : 1,
"customerName" : "AMIT"
}]
}
Error Message From Console:-
java.lang.IllegalArgumentException: Can not set int field com.example.demo.model.Customer.customerId to java.util.LinkedHashMap
Error Message On Postman:-
Error accessing field [int com.example.demo.model.Customer.customerId] by reflection for persistent property [com.example.demo.model.Customer#customerId] : {customerId=1, customerName=AMIT}; nested exception is org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [int com.example.demo.model.Customer.customerId] by reflection for persistent property [com.example.demo.model.Customer#customerId] : {customerId=1, customerName=AMIT}"
Need To add Generic type Customer argument in Set children Collection type.
Set<Customer> children;

Insert ID manually for JPA in Spring Boot

How can I insert id manually for this JPA entity in Spring boot? I don't want the id to be autogenerated. I tried sending a POST request using postman sending this JSON object to a RestController:
{
"id":"1",
"name":"New York"
}
I get an error saying that I should manually assing id. Why it is not taking the id that I'm passing in the request?
The Code:
Entity
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class City{
#Id
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long Id) {
this.Id = Id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Controller:
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class CityService{
private CityService cityService;
#Autowired
public void setCityService(CityService CityService) {
this.CityService = CityService;
}
#RequestMapping(method=RequestMethod.POST, value="/cities")
public void cities(#RequestBody City city){
cityService.save(city);
}
}
Service:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
#Service
public class CityService {
private CityRepository cityRepository;
#Autowired
public CityServiceImpl(CityRepository cityRepository) {
this.cityRepository= cityRepository;
}
#Override
public void saveCity(City city) {
CityRepository.save(city);
}
}
Theres probably something wrong with your setters. Try generating them again.
There was an old table with a different structure in the database. There was no error in the code.

Model is not managed by any plugin

I'm using Play!Framwork 1.2.5.
I'm trying to implement the CRUD in my project for my casses in models. I followed the steps described here, but I'm getting the following error:
Model models.Media is not managed by any plugin
at play.db.Model$Manager.factoryFor(Model.java:57)
at controllers.CRUD$ObjectType.<init>(CRUD.java:215)
at controllers.CRUD$ObjectType.get(CRUD.java:238)
at controllers.CRUD$ObjectType$get.call(Unknown Source)
at {module:crud}/app/views/tags/crud/types.tag.(line:4)
at play.templates.GroovyTemplate.internalRender(GroovyTemplate.java:247)
at play.templates.GroovyTemplate$ExecutableTemplate.invokeTag(GroovyTemplate.java:401)
at {module:crud}/conf/routes.(line:4)
at play.templates.GroovyTemplate.internalRender(GroovyTemplate.java:247)
at play.templates.Template.render(Template.java:26)
at play.templates.GroovyTemplate.render(GroovyTemplate.java:202)
at play.mvc.Router.parse(Router.java:162)
at play.mvc.Router.parse(Router.java:190)
at play.mvc.Router.parse(Router.java:164)
at play.mvc.Router.load(Router.java:48)
at play.mvc.Router.detectChanges(Router.java:219)
at Invocation.HTTP Request(Play!)
here is the code of the class media:
import org.hibernate.annotations.Entity;
import org.hibernate.annotations.GenericGenerator;
import play.db.jpa.Model;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
#Entity
public class Media extends Model{
#Id
private String uuid;
#OneToOne
private Video video;
#OneToOne
private Picture picture;
public String getUuid() {
return uuid;
}
public void setUuid(String id) {
this.uuid = id;
}
public Video getVideo() {
return video;
}
public void setVideo(Video video) {
this.video = video;
}
public Picture getPicture() {
return picture;
}
public void setPicture(Picture picture) {
this.picture = picture;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Media))
return false;
Media media = (Media) obj;
return media.getUuid().equals(this.uuid);
}
}
I think you are not used the right import statement.
Your import on Media.java model should be like below:
Media Model
import play.db.jpa.Model;
// should import javax.persistence.* package rather than org.hibernate.*
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;
#Entity
public class Media extends Model {
....
}
If you marked field with relationship annotation (like #OneToOne), you should define the object as an Entity. So, your other model such as Picture.java or Video.java should import the same kind with Media.java like below:
Picture Model
import play.db.jpa.Model;
// don't forget to import javax.persistence.* package
import javax.persistence.Entity;
#Entity
public class Picture extends Model {
...
}
Video Model
import play.db.jpa.Model;
// don't forget to import javax.persistence.* package too
import javax.persistence.Entity;
#Entity
public class Video extends Model {
...
}
I have tried this, and it works with me. Hope it helps to solve your problem.
Regards.

Categories