I develop an application that allows to manage the candidates, the application contains two tables (candidate and techno) joined with a #ManyToMany join table, I'm looking for how to fill both tables with the same #PostMapping, as my code indicates. I'm using an Angular application witch send a candidat with all the informations and a table of techno (that the candidat have to select, he can not add a new techno). I would like to join the new candidat with some techno. This is what the controller will receive:
{prenom: "Pname", nom: "Name", pseudo: "Pnamename", ecole: "school", mail: "email#email.com", …}
ecole: "school"
mail: "email#email.com"
nom: "Name"
numTel: "0123456789"
prenom: "Pname"
pseudo: "Pnamename"
roleCible: "poste"
secteurActivites: "sector"
techno: Array(3)
0: "android"
1: "drupal"
2: "html"
length: 3
__proto__: Array(0)
typeContrat: "CDI"
villeRecherchee: "Paris"
__proto__: Object
1- Candidat.java
#Entity
#Table(name = "Candidats")
public class Candidat {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String nom;
private String prenom;
private String ecole;
private String numTel;
private String mail;
private String pseudo;
private String roleCible;
private String typeContrat;
private String villeRecherchee;
#Temporal(TemporalType.DATE)
private Date dateCurrent = new Date();
#ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
#JoinTable(name = "candidat_techno", joinColumns = { #JoinColumn(name = "candidat_id") },
inverseJoinColumns = {
#JoinColumn(name = "techno_id") })
private Set<Techno> techno = new HashSet<>();
public Candidat() {
}
#SuppressWarnings("unchecked")
public Candidat(String nom, String prenom, String ecole, String numTel, String mail, String pseudo,
String roleCible, String typeContrat, String villeRecherchee, List<Techno> techno, Date dateCurrent,) {
super();
this.nom = nom;
this.prenom = prenom;
this.ecole = ecole;
this.numTel = numTel;
this.mail = mail;
this.pseudo = pseudo;
this.roleCible = roleCible;
this.typeContrat = typeContrat;
this.villeRecherchee = villeRecherchee;
this.techno = (Set<Techno>) techno;
this.dateCurrent = new Date();
//getters ans setters
2- CandidatController
#CrossOrigin(origins = "http://localhost:4200")
#RestController
#RequestMapping("/avatar")
public class CandidatController {
#Autowired
CandidatDao candidatdao;
#Autowired
TechnoDao technoDao;
#PostMapping(value = "/add-candidat")
public Candidat addCandidate(#RequestBody Candidat Candidat) {
Candidat candidatAdded = candidatdao.save(Candidat);
return candidatAdded;
technodao.save(Candidat.getTechno());
}
}
3- CandidatDAO
#Repository
public interface CandidatDao extends JpaRepository<Candidat, String> {
}
4-Techno.java
#Entity
#Table(name = "techno")
public class Techno {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String nomTechno;
#ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE }, mappedBy = "techno")
private Set<Candidat> candidat = new HashSet<Candidat>();
public Techno() {
}
#SuppressWarnings("unchecked")
public Techno(String nomTechno, Candidat candidat) {
super();
this.nomTechno = nomTechno;
this.candidat = (Set<Candidat>) candidat;
}
public String getNomTechno() {
return nomTechno;
}
public void setNomTechno(String nomTechno) {
this.nomTechno = nomTechno;
}
#Override
public String toString() {
return "Techno [nomTechno=" + nomTechno + ", candidat=" + candidat + "]";
}
//getters ans setters
5- TechnoController
#CrossOrigin(origins = "http://localhost:4200")
#RestController
#RequestMapping("/avatar")
public class TechnoController {
#Autowired
TechnoDao technodao;
#PostMapping(value = "/add-techno")
public Techno addCandidate(#RequestBody Techno Techno) {
Techno technoAdded = technodao.save(Techno);
return technoAdded;
}
}
6- TechnoDao
#Repository
public interface TechnoDao extends JpaRepository<Techno, String> {
Techno save(Set<Techno> techno);
}
for now I can fill both tables, but with two different post mapping.
how to fill both tables (techno and candidate) at the same time with a single #post mapping ?? like this:
{
id: 1,
nom: "smith",
prenom: "john",
ecole: "usa",
numTel: "11111",
mail: "j#smith",
pseudo: "JS",
roleCible: "usa",
typeContrat: "usa",
villeRecherchee: "paris",
dateCurrent: "2019-10-02",
techno: [
{
id: 1,
nomTechno: "springBoot"
},
{
id: 2,
nomTechno: "java"
}
]
}
In your CandidateController, Add this:
#Autowired
TechnoDao technoDao;
Inside post mapping use this:
technoDao.save(candidat.getTechno());
This has to help you.
Related
I am making a REST api in Java with Spring boot JPA Hibernate and with H2 database, I am trying to do a POST to "api/facturas" which is the RequestMapping of FacturaController, in which I want to add data to the FacturaDetalles List, but It returns an empty array, as if the data had never been sent, what am I doing wrong here?
I am trying to make a POST to "/api/facturas" like this:
{
"cliente": {
"idCliente": 1
},
"facturaDetalles": [
{
"producto": {
"idProducto": 3
}
}
]
}
This is what it should return:
{
"cliente": {
"idCliente": 1,
"nombreCliente": "Juan",
"apellidoCliente": "Rufiol",
"dni": 35884121,
"direccionCliente": "Av. Siempre Viva 300",
"telefonoCliente": 353654128,
"emailCliente": "juancito#gmail.com",
"cuit": 5412456985510,
"ciudad": "Capital Federal",
"provincia": "Buenos Aires",
"pais": "Argentina",
"codigoPostal": 1426,
"fechaNacimiento": "10-10-1980"
},
"facturaDetalles": [
{
"idFacturaDetalles": 1,
"producto": {
"idProducto": 3,
"nombreProducto": "Pollo frito",
"precioProducto": 40,
"descripcion": "Una delicia king chicken",
"stock": 3
}
}
]
}
This is what i get:
{
"cliente": {
"idCliente": 1,
"nombreCliente": "Juan",
"apellidoCliente": "Rufiol",
"dni": 35884121,
"direccionCliente": "Av. Siempre Viva 300",
"telefonoCliente": 353654128,
"emailCliente": "juancito#gmail.com",
"cuit": 5412456985510,
"ciudad": "Capital Federal",
"provincia": "Buenos Aires",
"pais": "Argentina",
"codigoPostal": 1426,
"fechaNacimiento": "10-10-1980"
},
"facturaDetalles": []
}
[data.sql]
INSERT INTO clientes (nombre,apellido,dni,direccion,telefono,email,cuit,ciudad,provincia,pais,codigo_postal, fecha_nacimiento ) VALUES ('Juan','Rufiol','35884121','Av. Siempre Viva 300','353654128','juancito#gmail.com','5412456985510','Capital Federal','Buenos Aires', 'Argentina',1426,'10-10-1980' );
INSERT INTO clientes (nombre,apellido,dni,direccion,telefono,email,cuit,ciudad,provincia,pais,codigo_postal, fecha_nacimiento ) VALUES ('Rolo','Garcia','41882121','Mariano Moreno 44','353614128','rolaso#rol.com','51134569854113','Capital Federal','Buenos Aires', 'Argentina',1426,'01-03-1989' );
INSERT INTO facturas (nro_factura,tipo_factura,precio_total_factura,id_cliente) VALUES (4444,'A',2000,1);
INSERT INTO facturas (nro_factura,tipo_factura,precio_total_factura,id_cliente ) VALUES (4444,'A',2000,1);
INSERT INTO facturas_detalles (cantidad,subtotal,id_facturas ,id_producto) VALUES (1,1,1,3);
INSERT INTO facturas_detalles (cantidad,subtotal,id_facturas ,id_producto) VALUES (1,1,1,2);
[Factura]
#Entity
#Table(name = "facturas")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Factura {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long idFactura;
#Column(name = "nro_factura")
private Integer nroFactura;
#Column(name = "tipo_factura")
private String tipoFactura;
#Column(name = "fecha", columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
private String fechaFactura;
#Column(name = "precio_total_factura")
private Integer precioTotalFactura;
#OneToOne
#JoinColumn(name = "id_cliente")
private Cliente cliente;
#JsonManagedReference
#OneToMany(mappedBy = "factura", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<FacturaDetalles> facturaDetalles = new ArrayList<>();
#OneToOne
#JoinColumn(name = "id_empresa")
private Empresa empresa;
}
[FacturaDTO]
#Data
#AllArgsConstructor
#NoArgsConstructor
public class FacturaDTO {
private ClienteDTO cliente;
private List<FacturaDetallesDTO> facturaDetalles;
}
[FacturaServiceImp]
#Service
public class FacturaServiceImp implements FacturaService {
#Autowired
private FacturaRepository facturaRepository;
public List<Factura> getAllFacturas() {
return facturaRepository.findAll();
}
public Factura getOneFactura(Long id) {
return facturaRepository.findById(id).orElseThrow(() -> new RuntimeException("Factura no encontrado"));
}
public Factura createFactura(Factura factura) {
return facturaRepository.save(factura);
}
public void deleteFactura(Long id) {
facturaRepository.deleteById(id);
}
}
[FacturaService]
public interface FacturaService {
List<Factura> getAllFacturas();
Factura getOneFactura(Long id);
Factura createFactura(Factura factura);
void deleteFactura(Long id);
}
[FacturaController]
#RestController
#RequestMapping("/api/facturas")
public class FacturaController {
#Autowired
ModelMapper modelMapper;
#Autowired
FacturaService facturaService;
#GetMapping()
public List<FacturaDTO> getAllFacturas() {
return facturaService.getAllFacturas().stream().map(factura -> modelMapper.map(factura, FacturaDTO.class)).collect(Collectors.toList());
}
#GetMapping("/{id}")
public ResponseEntity<FacturaDTO> getOneFactura(#PathVariable Long id) {
Factura factura = facturaService.getOneFactura(id);
FacturaDTO facturaDTO = modelMapper.map(factura, FacturaDTO.class);
return ResponseEntity.ok().body(facturaDTO);
}
#PostMapping()
public ResponseEntity<FacturaDTO> createFactura(#RequestBody FacturaDTO facturaDTO) {
Factura factura = modelMapper.map(facturaDTO, Factura.class);
Factura facturaCreacion = facturaService.createFactura(factura);
FacturaDTO conversion = modelMapper.map(facturaCreacion, FacturaDTO.class);
return new ResponseEntity<FacturaDTO>(conversion, HttpStatus.CREATED);
}
#DeleteMapping("/{id}")
public ResponseEntity<FacturaDTO> deleteFactura(#PathVariable Long id) {
Factura factura = facturaService.getOneFactura(id);
facturaService.deleteFactura(id);
FacturaDTO facturaDTO = modelMapper.map(factura, FacturaDTO.class);
return ResponseEntity.ok().body(facturaDTO);
}
}
[FacturaDetalles]
#Entity(name = "facturas_detalles")
#Table(name = "facturas_detalles")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class FacturaDetalles {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long idFacturaDetalles;
#Column(name = "cantidad")
private Integer cantidadProductos;
#Column(name = "subtotal")
private Integer totalParcial;
#JsonBackReference
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "id_facturas")
private Factura factura;
#OneToOne
#JoinColumn(name = "id_producto")
private Producto producto;
}
[FacturaDetallesDTO]
#Data
#AllArgsConstructor
#NoArgsConstructor
public class FacturaDetallesDTO {
private Long idFacturaDetalles;
private ProductoDTO producto;
}
[FacturaDetallesServiceImp]
#Service
public class FacturaDetallesServiceImp implements FacturaDetallesService {
#Autowired
private FacturaDetallesRepository facturaDetallesRepository;
public List<FacturaDetalles> getAllFacturaDetalles() {
return facturaDetallesRepository.findAll();
}
public FacturaDetalles getOneFacturaDetalles(Long id) {
return facturaDetallesRepository.findById(id).orElseThrow(() -> new RuntimeException("Factura no encontrado"));
}
public FacturaDetalles createFacturaDetalles(FacturaDetalles facturaDetalles) {
return facturaDetallesRepository.save(facturaDetalles);
}
public void deleteFacturaDetalles(Long id) {
facturaDetallesRepository.deleteById(id);
}
}
[FacturaDetallesService]
public interface FacturaDetallesService {
List<FacturaDetalles> getAllFacturaDetalles();
FacturaDetalles getOneFacturaDetalles(Long id);
void deleteFacturaDetalles(Long id);
FacturaDetalles createFacturaDetalles(FacturaDetalles facturaDetalles);
}
[FacturaDetallesController]
#RestController
#RequestMapping("/api/detalles")
public class FacturaDetallesController {
#Autowired
ModelMapper modelMapper;
#Autowired
FacturaDetallesService facturaDetallesService;
#GetMapping()
public List<FacturaDetallesDTO> getAllFacturaDetalles() {
return facturaDetallesService.getAllFacturaDetalles().stream().map(facturaDetalles -> modelMapper.map(facturaDetalles, FacturaDetallesDTO.class)).collect(Collectors.toList());
}
#GetMapping("/{id}")
public ResponseEntity<FacturaDetallesDTO> getOneFacturaDetalles(#PathVariable Long id) {
FacturaDetalles facturaDetalles = facturaDetallesService.getOneFacturaDetalles(id);
FacturaDetallesDTO detallesDTO = modelMapper.map(facturaDetalles, FacturaDetallesDTO.class);
return ResponseEntity.ok().body(detallesDTO);
}
#PostMapping()
public ResponseEntity<FacturaDetallesDTO> createFacturaDetalles(#RequestBody FacturaDetallesDTO facturaDetallesDTO) {
FacturaDetalles facturaDetalles = modelMapper.map(facturaDetallesDTO, FacturaDetalles.class);
FacturaDetalles facturaDetallesCreacion = facturaDetallesService.createFacturaDetalles(facturaDetalles);
FacturaDetallesDTO conversion = modelMapper.map(facturaDetallesCreacion, FacturaDetallesDTO.class);
return new ResponseEntity<FacturaDetallesDTO>(conversion, HttpStatus.CREATED);
}
#DeleteMapping("/{id}")
public ResponseEntity<FacturaDetallesDTO> deleteFacturaDetalles(#PathVariable Long id){
FacturaDetalles facturaDetalles = facturaDetallesService.getOneFacturaDetalles(id);
facturaDetallesService.deleteFacturaDetalles(id);
FacturaDetallesDTO detallesDTO = modelMapper.map(facturaDetalles, FacturaDetallesDTO.class);
return ResponseEntity.ok().body(detallesDTO);
}
}
try like this (lines omitted due to readability, e.g. checks)
#Autowired
private FacturaRepository facturaRepository;
#Autowired
private FacturaDetallesRepository facturaDetallesRepository;
public Factura createFactura(...) {
// get factura from db (by id from dto)
Factura factura = facturaRepository.findByIdFactura(facura.getIdFactura())
// get facturaDetalles from db (by id from dto)
FacturaDetalles facturaDetalles = facturaDetallesRepository.findByIdFacturaDetalles(...)
// link entites, for each detalles object!
facturaDetalles.setFactura(factura)
// add to list, but check if already in list first
factura.getFacturaDetalles().add(facturaDetalles)
facturaRepository.save(factura);
}
I have several entities
post
public class Post {
#Id
#SequenceGenerator(name = "jpaSequence.Post",
sequenceName = "SEQUENCE_POST",
allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "jpaSequence.Post")
private Long id;
private String subject;
#OneToMany(mappedBy = "post", fetch = FetchType.LAZY)
private List<Comment> comments = new ArrayList<>();
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn
private User user;
comment
#Entity
#Table(name = "comments")
public class Comment {
#Id
#SequenceGenerator(name = "jpaSequence.Comment",
sequenceName = "SEQUENCE_COMMENT",
allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "jpaSequence.Comment")
private Long id;
private String reply;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn
private Post post;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn
private User user;
user
#Entity
#Table(name = "users")
public class User {
#Id
#SequenceGenerator(name = "jpaSequence.User",
sequenceName = "SEQUENCE_USER",
allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "jpaSequence.User")
private Long id;
private String name;
private String email;
postDto
public class PostDto {
private Long id;
private String subject;
private List<CommentDto> comments = new ArrayList<>();
private UserDto user;
commentDto
public class CommentDto {
private Long id;
private String reply;
private PostDto post;
private UserDto user;
userDto
public class UserDto {
private Long id;
private String name;
private String email;
mapper
#Mapper(componentModel = "spring")
public interface PostMapper {
Post postDtoToPostEntity(PostDto dto);
#Mapping(target = "post.comments", ignore = true)
CommentDto toCommentDto(Comment entity);
#Mapping(target = "comments", source = "entity.comments", qualifiedBy = CommentListDtoAnnotation.class)
PostDto postEntityToPostDto(Post entity);
#CommentListDtoAnnotation
default Iterable<CommentDto> commentListEntityToCommentListDto(Iterable<Comment> source) {
Iterable<CommentDto> collect = StreamSupport.stream(source.spliterator(), false)
.map(this::toCommentDto)
.peek(dto -> dto.setPost(null))
.collect(Collectors.toList());
return collect;
}
Iterable<Post> postListDtoToPostListEntity(Iterable<PostDto> list);
Iterable<PostDto> postListEntityToPostListDto(Iterable<Post> list);
}
commentMapper
#Mapper(componentModel = "spring")
public interface CommentMapper {
Comment commentDtoToCommentEntity (CommentDto dto);
#Mapping(target = "post.comments", ignore = true)
CommentDto commentEntityToCommentDto(Comment entity);
Iterable<Comment> commentListDtoToCommentListEntity(Iterable<CommentDto> list);
Iterable<CommentDto> commentListEntityToCommentListDto(Iterable<Comment> list);
}
annotation
import org.mapstruct.Qualifier;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Qualifier
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.CLASS)
public #interface CommentListDtoAnnotation {
}
But when the mapping takes place I get the following response:
{
"id": 1,
"subject": "JPA Entity Graph In Action",
"comments": [
{
"id": 1,
"reply": "Nice !!",
"post": {
"id": 1,
"subject": "JPA Entity Graph In Action",
"comments": [],
"user": {
"id": 1,
"name": "user1",
"email": "user1#test.com"
}
},
"user": {
"id": 2,
"name": "user2",
"email": "user2#test.com"
}
},
{
"id": 2,
"reply": "Cool !!",
"post": {
"id": 1,
"subject": "JPA Entity Graph In Action",
"comments": [],
"user": {
"id": 1,
"name": "user1",
"email": "user1#test.com"
}
},
"user": {
"id": 3,
"name": "user3",
"email": "user3#test.com"
}
}
],
"user": {
"id": 1,
"name": "user1",
"email": "user1#test.com"
}
}
Update_1
service
#Service
public class PostReadServiceImpl implements PostReadService {
private PostRepository repository;
private PostWithoutNestedLevelsTransformers transformer;
#Autowired
public PostReadServiceImpl(PostRepository repository,
PostWithoutNestedLevelsTransformers transformer) {
this.repository = repository;
this.transformer = transformer;
}
#Override
public PostDto getEntryById(Long id) {
Post entity = findEntry(id);
PostDto postDto = this.transformer.transformEntityToDto(entity);
return postDto;
}
private Post findEntry(Long id) {
return this.repository.findById(id).orElseThrow(() -> new RuntimeException("Post not found!"));
}
#Transactional
#Override
public Iterable<PostDto> getListPosts() {
Iterable<Post> posts = findListPosts();
Iterable<PostDto> postDtoList = this.transformer.transformListEntityToDtoList(posts);
return postDtoList;
}
private Iterable<Post> findListPosts() {
Iterable<Post> posts = this.repository.findAll();
return posts;
}
private Iterable<Comment> pickUpComment (List<Comment> comments ) {
List<Comment> listComment = new ArrayList<>();
for (Comment comment : comments) {
Comment conversionComment = moveData(comment);
listComment.add(conversionComment);
}
return listComment;
}
private Comment moveData(Comment comment) {
Comment conversionComment = new Comment();
String commentReply = comment.getReply();
Long idUser = comment.getId();
conversionComment.setId(idUser);
conversionComment.setReply(commentReply);
return conversionComment;
}
}
transformer
#Component
public class PostTransformer {
private PostMapper mapper;
#Autowired
public PostTransformer(PostMapper mapper) {
this.mapper = mapper;
}
public PostDto transformEntityToDto(Post entity) {
PostDto postDto = this.mapper.postEntityToPostDto(entity);
return postDto;
}
public Post transformDtoToEntity(PostDto dto) {
return this.mapper.postDtoToPostEntity(dto);
}
public Iterable<PostDto> transformListEntityToDtoList(Iterable<Post> listEntity) {
Iterable<PostDto> postDtoList = this.mapper.postListEntityToPostListDto(listEntity);
return postDtoList;
}
public Iterable<Post> transformListDtoToEntityList(Iterable<PostDto> listDto) {
return this.mapper.postListDtoToPostListEntity(listDto);
}
}
The method must be executed:
#CommentListDtoAnnotation
default Iterable<CommentDto> commentListEntityToCommentListDto(Iterable<Comment> source) {
But it is not.
In the field comment, nested field - post - must be null...
I don't understand what I'm doing wrong.
I wish to have subquery, which provides me filtering actors by name.
I have a rest controller's method, which returns list of actors as JSON from movie base on movieId. I try to add filters as specification, but I have no idea how to write proper query. Base on "Spring Data JPA Specification for a ManyToMany Unidirectional Relationship" I found solution for subquery, which returns me all actors to proper movie base on movieId. Now I try to write this query.
Actor entity
#Data
#NoArgsConstructor
#Entity
#Table(name = "actors")
public class Actor implements Serializable {
private static final long serialVersionUID = 6460140826650392604L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "actor_id")
private Long actorId;
#Column(name = "first_name")
private String firstName;
#ManyToMany(mappedBy = "actors")
#ToString.Exclude
private List<Movie> movie = new ArrayList<>();
#JsonIgnore
public List<Movie> getMovie() {
return this.movie;
}
}
Movie entity
#Data
#Entity
#NoArgsConstructor
#Table(name = "movies")
public class Movie implements Serializable {
private static final long serialVersionUID = 3683778473783051508L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "movie_id")
private Long movieId;
private String title;
#ManyToMany(cascade = { CascadeType.ALL })
#JoinTable(name = "movies_actors"
, joinColumns = { #JoinColumn(name = "movie_id") }
, inverseJoinColumns = { #JoinColumn(name = "actor_id") })
private List<Actor> actors = new ArrayList<>();
#JsonIgnore
public List<Actor> getActors() {
return this.actors;
}
}
//Rest Controller
#CrossOrigin(origins = "http://localhost:3000")
#RestController
#RequestScope
#RequestMapping("/rest")
public class ActorRestController {
private ActorService actorService;
private MovieService movieService;
#Autowired
public ActorRestController(ActorService actorService, MovieService movieService) {
this.actorService = actorService;
this.movieService = movieService;
}
.
.
.
#GetMapping("movies/{movieId}/actors")
public ResponseEntity<Page<Actor>> getAllActorsFromMovieByIdMovie(#PathVariable(name = "movieId") Long movieId, Pageable pageable) {
Optional<Movie> movieFromDataBase = movieService.findMovieById(movieId);
if (movieFromDataBase.isPresent()) {
return new ResponseEntity<>(actorService.findAllActors(ActorSpec.query(movieId), pageable), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
.
.
}
// Specification for actor
#NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ActorSpec {
public static Specification<Actor> query(final Long movieId) {
return (root, query, cb) -> {
query.distinct(true);
Subquery<Movie> movieSubQuery = query.subquery(Movie.class);
Root<Movie> movie = movieSubQuery.from(Movie.class);
Expression<List<Actor>> actors = movie.get("actors");
movieSubQuery.select(movie);
movieSubQuery.where(cb.equal(movie.get("movieId"), movieId), cb.isMember(root, actors));
return cb.exists(movieSubQuery);
};
}
}
I would like, my code will return filtered actors by name ex.:
http://localhost:8080/rest/movies/48/actors?name=Collin
will return me
{ "actorId": 159,
"firstName": "Collin",
"lastName": "Konopelski",
"age": 21
},
but in case I do not sent any request param (http://localhost:8080/rest/movies/48/actors), let program return me all actors. I don't want to create new endpoint only for #Requestparam cause, this one is used by UI created in React.
Thanks!
Ok I found,
My solution:
RestController
#GetMapping("movies/{movieId}/actors")
public ResponseEntity<Page<Actor>> getAllActorsFromMovieByIdMovie(#PathVariable(name = "movieId") Long movieId,
#RequestParam(name = "name", required = false) String name,
Pageable pageable) {
Optional<Movie> movieFromDataBase = movieService.findMovieById(movieId);
if (movieFromDataBase.isPresent()) {
return new ResponseEntity<>(actorService.findAllActors(ActorSpec.query(movieId ,name), pageable), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
Specification
#NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ActorSpec {
public static Specification<Actor> query(final Long movieId, String name) {
return (root, query, cb) -> {
Predicate predicateMovieID = getPredicateByMovieId(movieId, root, query, cb);
if (Strings.isNotBlank(name)) {
Predicate a = cb.and(predicateMovieID, cb.equal(root.get("firstName"), name));
Predicate b = cb.and(predicateMovieID, cb.equal(root.get("lastName"), name));
return cb.or(a,b);
}
return cb.and(predicateMovieID);
};
}
private static Predicate getPredicateByMovieId(Long movieId, Root<Actor> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
query.distinct(true);
Subquery<Movie> movieSubQuery = query.subquery(Movie.class);
Root<Movie> movie = movieSubQuery.from(Movie.class);
Expression<List<Actor>> actors = movie.get("actors");
movieSubQuery.select(movie);
movieSubQuery.where(cb.equal(movie.get("movieId"), movieId), cb.isMember(root, actors));
return cb.exists(movieSubQuery);
}
}
I am working with a project .I use springboot and Jpa.It works perfectly and insert data into DB when Program runs.But when i want to save data via postman then it shows BadRequest.How can i create my controller for this kind of classes. like:
CrickerPlayer:
public class CricketPlayer extends PlayerProfile {
#Id
private String playerId;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "cricketPlayer")
private List<Performance> performanceList;
#ManyToMany(fetch = FetchType.EAGER)
#JoinColumn(name = "play_for_Team")
private List<PlayForTeam> playForTeamList;
//getters and setters
}
PlayerProfile:
public class PlayerProfile {
private String image;
private String name;
private int age;
private LocalDate dob;
private double height;
private String nationality;
private int jerseyNo;
private String game;
}
Performance.class
public class Performance {
#Id
private String performanceId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "id")
private Game match;
private long[] runsScored;
private int fours;
private int sixes;
private int ballsFaced;
private String[] oversBowled;
private int bowled;
private int wickets;
private double BattingAverage;
private double BowlingAverage;
private double economy;
private int totalStumping;
private double strikeRate;
private int highestScore;
private int totalMaidens;
private int totalCatches;
#OneToMany(cascade = CascadeType.ALL)
private List<Role> performanceRoleList;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "player_id")
private CricketPlayer cricketPlayer;
}
There's some entity also Ground,series game and a Gametype enum. like:
Game.class
public class Game {
#Id
private String id;
#Enumerated
private MatchType matchType;
#OneToOne(cascade = CascadeType.ALL)
private Ground ground;
#OneToOne(cascade = CascadeType.ALL)
private Series series;
#OneToMany(cascade = CascadeType.ALL)
private List<CricketPlayer> cricketPlayers;
}
Ground.class
public class Ground {
#Id
private String groundId;
private String groundName;
}
MatchType.enum
public enum MatchType {
ODI,
TEST,
T20,
T10;
}
RestController.class
#Controller
#RequestMapping(value = "api/cricketplayer")
#AllArgsConstructor
public class CricketPlayerRest {
#Autowired
private final CricketPlayerService cricketPlayerService;
private Game game1;
private Ground ground1;
private Series series1;
private Performance performance1;
private Role role1;
private PlayForTeam playForTeam1;
private CricketPlayer cricketPlayer1;
private WrapperClass wrapperClass;
List<Performance> performanceList = new ArrayList<>();
List<PlayForTeam> playForTeamList = new ArrayList<>();
List<Role> roleList = new ArrayList<>();
List<CricketPlayer> playForTeamCricketer = new ArrayList<>();
List<CricketPlayer> gameListForCricketer = new ArrayList<>();
#GetMapping(value = "all")
#ResponseBody
public ResponseEntity<?> getAllPlayers() {
return ResponseEntity.status(HttpStatus.OK).body(cricketPlayerService.findAllPlayers());
}
#GetMapping(value = "name")
#ResponseBody
public ResponseEntity<?> getPlayerByName(#RequestParam String name) {
Optional<CricketPlayer> cricketPlayer = cricketPlayerService.getPlayerByName(name);
if (cricketPlayer.isPresent()) {
return ResponseEntity.status(HttpStatus.OK).body(cricketPlayer.get());
} else {
return ResponseEntity.badRequest().body(null);
}
}
#GetMapping(value = "{id}")
public ResponseEntity<?> getPlayerById(#PathVariable String id) {
Optional<CricketPlayer> cricketPlayer = cricketPlayerService.findPlayersById(id);
if (cricketPlayer.isPresent()) {
return ResponseEntity.status(HttpStatus.OK).body(cricketPlayer.get());
} else {
return ResponseEntity.badRequest().body(null);
}
}
#PostMapping(value = "save",
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<?> createPlayer(#RequestBody CricketPlayer cricketPlayer) {
try {
CricketPlayer createdPlayer = cricketPlayerService.save(cricketPlayer);
ResponseEntity<CricketPlayer> cricketPlayerResponseEnity = ResponseEntity
.status(HttpStatus.CREATED)
.body(createdPlayer);
return cricketPlayerResponseEnity;
} catch (Exception e) {
return ResponseEntity.badRequest().body(null);
}
}
}
There also repository for every entity.
Can anyone help me out for this project that how can i update a cricketPlayer with setting every entity.
My project link is: You see it here also in github
Postman data:
{
"image": "Musta",
"name": "Musta",
"age": 28,
"dob": "1985-04-02",
"height": 167,
"nationality": "Bangladeshi",
"jerseyNo": 28,
"game": "Cricket",
"playerId": "Musta",
"performanceList": [
{
"performanceId": "BD-NZ",
"match": {
"id": "1",
"matchType": "ODI",
"ground": {
"groundId": "Mirpur",
"groundName": "SHERE Bangla"
},
"series": {
"seriesId": "Walton",
"seriesName": "walton Series"
}
},
"runsScored": [
2,
0,
1,
3,
4,
6
],
"fours": 4,
"sixes": 2,
"ballsFaced": 12,
"oversBowled": [
"w",
"2",
"6",
"1",
"4",
"0"
],
"bowled": 0,
"wickets": 1,
"economy": 5.4,
"totalStumping": 1,
"strikeRate": 154.4,
"highestScore": 154,
"totalMaidens": 0,
"totalCatches": 5,
"performanceRoleList": [
{
"roleId": 3,
"type": "All-Rounder"
}
],
"bowlingAverage": 31.6,
"battingAverage": 25
}
],
"playForTeamList": [
{
"pftId": "sun",
"team": {
"id": "sun",
"teamName": "sun"
},
"startsDate": "2011-03-01",
"endsDate": "2013-03-31"
}
]
}
I have a problem to create a POST or a GET request in postman. I have an controller that suppose to save a new project or to receive all projects from DB.
If I try to save a project in a class that implements CommandLineRunner in database it's everything ok. For more extra details I put my code below:
This is Project class:
#Entity
#Table(name = "project")
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "proj_id")
private int projectId;
#Column(name = "project_name")
private String projectName;
#Column(name = "dg_number")
private int dgNumber;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
name = "variant_gate_relation",
joinColumns = {#JoinColumn(name = "proj_id")},
inverseJoinColumns = {#JoinColumn(name = "gate_id")}
)
private Set<Gate> gates = new HashSet<>();
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "variant_threshold_relation",
joinColumns = #JoinColumn(name = "proj_id"),
inverseJoinColumns = #JoinColumn(name = "threshold_id"))
private Set<Threshold> thresholds = new HashSet<>();
public Project() {
}
public Project(String projectName, int dgNumber, Set<Gate> gates, Set<Threshold> thresholds){
this.projectName = projectName;
this.dgNumber = dgNumber;
this.gates = gates;
this.thresholds = thresholds;
}
Controller
#RestController
#RequestMapping(ProjectController.PROJECT_URL)
public class ProjectController {
public static final String PROJECT_URL = "/cidashboard/projects";
#Autowired
private final ProjectService projectService;
public ProjectController(ProjectService projectService) {
this.projectService = projectService;
}
#GetMapping
public List<Project> getAllProjects(){
return projectService.findAllProjects();
}
#GetMapping("/{id}")
public Project getProjectById(#PathVariable int id) {
return projectService.findProjectById(id);
}
#PostMapping
// #Consumes(MediaType.APPLICATION_JSON_VALUE)
public Project saveProject(#RequestBody Project newProj) {
return projectService.saveProject(newProj);
}
}
This is my CommandLineRunner
#Component
public class Test implements CommandLineRunner {
private final ProjectRepository projectRepository;
private final GateRepository gateRepository;
private final ThresholdRepository thresholdRepository;
public Test(ProjectRepository projectRepository, GateRepository gateRepository, ThresholdRepository thresholdRepository) {
this.projectRepository = projectRepository;
this.gateRepository = gateRepository;
this.thresholdRepository = thresholdRepository;
}
#Override
public void run(String... args) throws Exception {
Gate gate1 = new Gate("gate5", 23);
gateRepository.save(gate1);
Threshold threshold1 = new Threshold(101, "threshold5");
thresholdRepository.save(threshold1);
Set<Gate> gates = new HashSet<>();
gates.add(gate1);
Set<Threshold> thresholds = new HashSet<>();
thresholds.add(threshold1);
Project project1 = new Project("project1", 20, gates, thresholds);
projectRepository.save(project1);
List<Project> allProjectsFromDatabase = projectRepository.findAll();
System.out.println("List of all projects from database : ");
for (Project project : allProjectsFromDatabase) {
System.out.println(project.toString());
}
System.out.println("---------------------------------------------");
List<Gate> allGatesFromDatabase = gateRepository.findAll();
for (Gate gate : allGatesFromDatabase) {
System.out.println(gate);
}
}
}
My output from console is :
1 project1 201 gate5 23.0 threshold5 101
I try to do this request from Postman:
{
"projectName": "project2",
"dgnumber": 1,
"gates": {
"gateType" : "gate2",
"gateValue" : 13
},
"thresholds": {
"thresholdType" : "threshold2",
"thresholdValue" : 22
}
}
And I receive the following output :
{
"projectId": 3,
"projectName": "project2",
"dgnumber": 1
}
And in DB only in project table the data was save, in gate table, threshold table, variant_gate_relation and variant_threshold_relation didn't save nothing
In your CommandLineRunner, you do this before saving the project.
Gate gate1 = new Gate("gate5", 23);
gateRepository.save(gate1);
Threshold threshold1 = new Threshold(101, "threshold5");
thresholdRepository.save(threshold1);
Set<Gate> gates = new HashSet<>();
gates.add(gate1);
Set<Threshold> thresholds = new HashSet<>();
thresholds.add(threshold1);
You should replicate that when saving from endpoint as well (the gateRepository.save() and thresholdRepository.save() are relevant here).