IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Spring Web Java Discussion :

Spring Rest API + Docker Compose + Postgres: GET ERROR 500 AFTER POST


Sujet :

Spring Web Java

  1. #1
    Membre régulier
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juin 2011
    Messages
    258
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2011
    Messages : 258
    Points : 76
    Points
    76
    Par défaut Spring Rest API + Docker Compose + Postgres: GET ERROR 500 AFTER POST
    Bonjour à tous,

    Tout est résumé dans le titre.
    Je fabrique une API pour un forum de rencontres entre musiciens.

    Mon projet Spring REST est basé sur celui ci:
    https://spring.io/guides/tutorials/rest/

    Au détail près que j'ai une base de données Postgres, et que tout est sur Docker (API + BDD) avec Docker Compose.

    VOICI LA STRUCTURE DU PROJET;

    Nom : Screenshot from 2022-01-17 18-30-14.png
Affichages : 503
Taille : 138,6 Ko



    VOICI LE CODE POUR UNE ENTITE:

    ENTITE:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
     
    package com.praline40.MeetZicker.Style;
     
    import com.praline40.MeetZicker.Group.Group;
    import com.praline40.MeetZicker.Musician.Musician;
     
    import javax.persistence.*;
    import java.util.ArrayList;
    import java.util.List;
     
    @Entity
    public class Style {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
     
        private String name;
     
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
     
        @ManyToMany(mappedBy = "styles")
        private List<Musician> musicians = new ArrayList<>();
     
        @ManyToMany(mappedBy = "styles")
        private List<Group> groups = new ArrayList<>();
     
        public Long getId() {
            return id;
        }
        public void setId(Long id) {
            this.id = id;
        }
     
        public List<Musician> getMusicians() {
            return musicians;
        }
        public void setMusicians(List<Musician> musicians) {
            this.musicians = musicians;
        }
     
        public List<Group> getGroups() {
            return groups;
        }
        public void setGroups(List<Group> groups) {
            this.groups = groups;
        }
    }
    CONTROLLER:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
     
    package com.praline40.MeetZicker.Style;
     
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.hateoas.CollectionModel;
    import org.springframework.hateoas.EntityModel;
    import org.springframework.hateoas.IanaLinkRelations;
    import org.springframework.hateoas.MediaTypes;
    import org.springframework.hateoas.mediatype.problem.Problem;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;
     
    import java.util.List;
    import java.util.stream.Collectors;
     
    import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
    import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
     
    @RestController //Combination of @Controller and @ResponseBody. Beans returned are converted to/from JSON/XML.
    public class StyleController {
        //@Autowired // Autowire the StyleRepository so that we can retrieve and save data to database.
        private final StyleRepository repository;
        private final StyleModelAssembler assembler; // Injecting StyleModelAssembler into the controller
     
        StyleController(StyleRepository repository, StyleModelAssembler assembler) {
            this.repository = repository;
            this.assembler = assembler;
        }
     
        @GetMapping("/styles/{id}")
        EntityModel<Style> one(@PathVariable Long id) {
     
            Style style = repository.findById(id) //
                    .orElseThrow(() -> new StyleNotFoundException(id));
     
            return assembler.toModel(style);
        }
     
        @GetMapping("/allstyles")
        public String allStyles(){
            return "You wanna know all styles !!";
        }
     
        @GetMapping("/styles")
        CollectionModel<EntityModel<Style>> all() {
     
            List<EntityModel<Style>> styles = repository.findAll().stream()
                    .map(assembler::toModel)
                    .collect(Collectors.toList());
     
            return CollectionModel.of(styles,
                    linkTo(methodOn(StyleController.class).all()).withSelfRel());
        }
     
        @PostMapping("/styles")
        ResponseEntity<?> newStyle(@RequestBody Style newStyle) {
     
            EntityModel<Style> entityModel = assembler.toModel(repository.save(newStyle));
     
            return ResponseEntity //
                    .created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri()) //
                    .body(entityModel);
        }
     
        @PutMapping("/styles/{id}")
        ResponseEntity<?> replaceStyle(@RequestBody Style newStyle, @PathVariable Long id) {
     
            Style updatedStyle = repository.findById(id) //
                    .map(style -> {
                        style.setName(newStyle.getName());
                        style.setMusicians(newStyle.getMusicians());
                        style.setGroups(newStyle.getGroups());
                        return repository.save(style);
                    }) // s'il n'existe pas déjà on le créé
                    .orElseGet(() -> {
                        newStyle.setId(id);
                        return repository.save(newStyle);
                    });
     
            EntityModel<Style> entityModel = assembler.toModel(updatedStyle);
     
            return ResponseEntity //
                    .created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri()) //
                    .body(entityModel);
        }
     
        @DeleteMapping("/styles/{id}")
        ResponseEntity<?> deleteStyle(@PathVariable Long id) {
     
            repository.deleteById(id);
     
            return ResponseEntity.noContent().build();
        }
    }

    ASSEMBLER:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    package com.praline40.MeetZicker.Style;
     
    import org.springframework.hateoas.EntityModel;
    import org.springframework.hateoas.server.RepresentationModelAssembler;
    import org.springframework.stereotype.Component;
     
    import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
    import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
     
    @Component
    public class StyleModelAssembler implements RepresentationModelAssembler<Style, EntityModel<Style>> {
     
        @Override
        public EntityModel<Style> toModel(Style style) {
     
            return EntityModel.of(style, //
                    linkTo(methodOn(StyleController.class).one(style.getId())).withSelfRel(),
                    linkTo(methodOn(StyleController.class).all()).withRel("styles"));
        }
    }
    NOT FOUND EXCEPTIONS:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    package com.praline40.MeetZicker.Style;
     
    class StyleNotFoundException extends RuntimeException {
     
        StyleNotFoundException(Long id) {
            super("Could not find style " + id);
        }
    }
    REPOSTITORY:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    package com.praline40.MeetZicker.Style;
     
    import org.springframework.data.jpa.repository.JpaRepository;
     
    interface StyleRepository extends JpaRepository<Style, Long> {
    }
    DOCKERFILE:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    FROM openjdk:11
    ADD target/meetzicker.jar meetzicker.jar
    ENTRYPOINT ["java", "-jar","meetzicker.jar"]
    EXPOSE 8080
    DOCKER-COMPOSE:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    version: '2.1'
    services:
      API:
        image: 'meetzicker.jar:latest'
        ports:
          - "8080:8080"
        depends_on:
          db:
            condition: service_healthy
        environment:
          - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/${POSTGRES_DB}
          - SPRING_DATASOURCE_USERNAME=${POSTGRES_USER}
          - SPRING_DATASOURCE_PASSWORD=${POSTGRES_PASSWORD}
          - SPRING_JPA_HIBERNATE_DDL_AUTO=update
     
      db:
        image: postgres:${POSTGRES_VERSION}
        ports:
          - "5432:5432"
        environment:
          - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
          - POSTGRES_USER=${POSTGRES_USER}
          - POSTGRES_DB=${POSTGRES_DB}
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U postgres"]
          interval: 10s
          timeout: 5s
          retries: 5



    DANS POSTMAN:

    D'abord un post qui fonctionne:
    Nom : Screenshot from 2022-01-17 18-12-13.png
Affichages : 491
Taille : 46,2 Ko

    Ensuite un get qui crashe:
    GET http://localhost:8080/styles

    Nom : Screenshot from 2022-01-17 18-13-49.png
Affichages : 481
Taille : 34,8 Ko


    NB: tant que je ne fais pas de POST, le GET fonctionne (du moins pour les entités indépendantes)!

    Nom : Screenshot from 2022-01-17 18-14-53.png
Affichages : 486
Taille : 31,3 Ko


    Un post pour un nouvel instrument:

    Nom : Screenshot from 2022-01-17 18-28-08.png
Affichages : 482
Taille : 54,7 Ko


    Ensuite un get, pareil ça plante:
    Nom : Screenshot from 2022-01-17 18-29-18.png
Affichages : 476
Taille : 39,4 Ko


    POUR CE CONTROLLER SIMPLIFIE PAS DE SOUCIS:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    package com.praline40.MeetZicker;
     
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.hateoas.CollectionModel;
    import org.springframework.hateoas.EntityModel;
    import org.springframework.hateoas.IanaLinkRelations;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;
     
    import java.util.List;
    import java.util.stream.Collectors;
     
    import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
    import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
     
    @RestController //Combination of @Controller and @ResponseBody. Beans returned are converted to/from JSON/XML.
    public class HomeController {
     
        @GetMapping("/")
        public String home(){
            return "Welcome to Meetzicker !!";
        }
    }
    Nom : Screenshot from 2022-01-17 18-33-32.png
Affichages : 474
Taille : 27,2 Ko


    J'y connais pas grand chose, mais comme ça je dirais que cela vient d'un soucis entre mes relations entre entitées (relations base de données). Car pourquoi cela marcherait-il tant que la base de données est vide (avant POST) ?
    J'avoue j'y suis allé de façon un peu bourrin j'ai fait directement une architecture relationnelle poussée.



  2. #2
    Membre confirmé
    Avatar de Jacques Beauregard
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mai 2015
    Messages
    231
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2015
    Messages : 231
    Points : 595
    Points
    595
    Par défaut
    Bonjour,

    Car pourquoi cela marcherait-il tant que la base de données est vide (avant POST) ?
    On peut l'expliquer par le fait qu'un GET qui retourne aucun résultat va passer, mais dès qu'un élément est présent en bdd (après l'exécution de ton post) le GET échoue et erreur 500 (une erreur 500 est côté serveur justement) car exception lors de la lecture de ta donnée. tu as une stacktrace d'ailleurs ?

    Si j'étais toi donc :

    • Je rajouterais une couche Service qui va appeler ton repository. Ce n'est pas le rôle du Controller. Chaque couche sa responsabilité aidera au passage au debug
    • Dans ta nouvelle couche service je rajouterais un système d'exception lors de l'appelle au repository (qui se charge de faire un SELECT...)
    • As-tu essayé (après ton POST) d'exécuter ton SELECT indépendemment pour voir si la requête passait ?


    Cdlt.

  3. #3
    Membre régulier
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juin 2011
    Messages
    258
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2011
    Messages : 258
    Points : 76
    Points
    76
    Par défaut
    Merci pour ta réponse. Je viens de me rendre compte que je n'ai pas été capable de recopier le projet d'exemple correctement, il manque cette classe:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
     
    package payroll;
     
    import org.springframework.http.HttpStatus;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.ResponseStatus;
     
     
    /*
    When an EmployeeNotFoundException is thrown, this extra tidbit of Spring MVC configuration is used to render an HTTP 404:
     
    - @ResponseBody signals that this advice is rendered straight into the response body.
    - @ExceptionHandler configures the advice to only respond if an EmployeeNotFoundException is thrown.
    - @ResponseStatus says to issue an HttpStatus.NOT_FOUND, i.e. an HTTP 404.
    - The body of the advice generates the content. In this case, it gives the message of the exception.
     */
     
    @ControllerAdvice
    class EmployeeNotFoundAdvice {
        @ResponseBody
        @ExceptionHandler(EmployeeNotFoundException.class)
        @ResponseStatus(HttpStatus.NOT_FOUND)
        String employeeNotFoundHandler(EmployeeNotFoundException ex) {
            return ex.getMessage();
        }
    }
    C'est sûrement cela le soucis... j'ai pas encore testé je dois bouger, je te tiens au ju !!

  4. #4
    Membre régulier
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juin 2011
    Messages
    258
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2011
    Messages : 258
    Points : 76
    Points
    76
    Par défaut
    J'ai donc toujours le meme soucis;
    J'ai un projet exemple avec Service-repo-controller je vais m'en inspirer.
    Si tu as des liens de tutoriels avec des services je veux bien m'en inspirer aussi.

  5. #5
    Membre confirmé
    Avatar de Jacques Beauregard
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mai 2015
    Messages
    231
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2015
    Messages : 231
    Points : 595
    Points
    595
    Par défaut
    Re,

    As-tu un log d'erreur plus détaillé que "internal servor error" ?

  6. #6
    Membre régulier
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juin 2011
    Messages
    258
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2011
    Messages : 258
    Points : 76
    Points
    76
    Par défaut
    A quel endroit je peut débugguer ça pour avoir plus d'infos ?

    J'avais un service pour les Concerts mais j'ai le même soucis: le post fonctionne mais pas le get.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
     
    package com.praline40.MeetZicker.Concert;
    import java.time.LocalDate;
    import java.util.List;
     
    import javax.annotation.PostConstruct;
     
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
     
    @Service
    public class ConcertService {
     
        @Autowired
        private ConcertRepository concertRepository;
     
        @Transactional
        @PostConstruct
        public void init() {
            concertRepository.save(new Concert(1L, "JerryTom", null, null, null, "La Roche sur Yon place du marché"));
        }
     
        public List<Concert> findAll() {
            return concertRepository.findAll();
        }
    }

    Apparemment ce service fonctionne puisque lorsque je post un nouveau concert, son ID est "2", ce qui laisse présupposer que le concert de JerryTom créé automatiquement par le service est bien existant.
    Nom : Screenshot from 2022-01-25 11-17-52.png
Affichages : 457
Taille : 55,2 Ko



    Comment dois-je modifier les classes services pour que ça fonctionne ?

    Le problème c'est que dans ces nouvelles technologies web y a tellement de tutoriels différents avec des méthodes sensiblement différentes que l'on ne sait plus à quoi se fier... J'ai suivi ce tutoriel :

    https://spring.io/guides/tutorials/rest/

    Apparemment il s'agit d'une vraie application RestFul 100%.

    Mais il n y a pas de service dans le projet...

  7. #7
    Membre régulier
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juin 2011
    Messages
    258
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2011
    Messages : 258
    Points : 76
    Points
    76
    Par défaut
    J'ai donc installé le plugin Docker pour pouvoir débugger.

    Voici l'erreur que j'ai lors d'un get:

    022-02-09 23:30:14.243 WARN 1 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: com.praline40.MeetZicker.Style.Style.musicians, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.praline40.MeetZicker.Style.Style.musicians, could not initialize proxy - no Session (through reference chain: org.springframework.hateoas.CollectionModel["_embedded"]->java.util.LinkedHashMap["styleList"]->java.util.ArrayList[0]->org.springframework.hateoas.EntityModel["content"]->com.praline40.MeetZicker.Style.Style["musicians"])]

  8. #8
    Membre émérite
    Homme Profil pro
    Ingénieur en génie logiciel
    Inscrit en
    Juin 2012
    Messages
    905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur en génie logiciel
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Juin 2012
    Messages : 905
    Points : 2 575
    Points
    2 575
    Par défaut
    le problème est dans ta gestion des relations, le message est assez claire
    montre ton code de Musician et Group

  9. #9
    Membre régulier
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juin 2011
    Messages
    258
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2011
    Messages : 258
    Points : 76
    Points
    76
    Par défaut
    Entity "Musician":

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
     
    package com.praline40.MeetZicker.Musician;
     
    import com.praline40.MeetZicker.Instrument.Instrument;
    import com.praline40.MeetZicker.MRG.MRG;
    import com.praline40.MeetZicker.MRM.MRM;
    import com.praline40.MeetZicker.Style.Style;
    import com.praline40.MeetZicker.SubInstrument.SubInstrument;
    import com.praline40.MeetZicker.Town.Town;
     
    import javax.persistence.*;
    import java.util.ArrayList;
    import java.util.List;
     
    @Entity
    @Table(name="Musicians")
    public class Musician {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String surName;
        private String lastName;
        private String firstName;
        private boolean sex;
        private int age;
        private boolean available; // le musicien affiche sa disponibilité
     
        @ManyToMany
        @JoinTable(name = "Musicians_Instruments",
                joinColumns = @JoinColumn(name = "musician_id"),
                inverseJoinColumns = @JoinColumn(name = "instrument_id"))
        private List<Instrument> instruments = new ArrayList<>(); // Liste de tous les instruments joués par ce musicien
     
        @ManyToMany
        @JoinTable(name = "Musicians_SubInstruments",
                joinColumns = @JoinColumn(name = "musician_id"),
                inverseJoinColumns = @JoinColumn(name = "subInstrument_id"))
        private List<SubInstrument> subInstruments = new ArrayList<>(); // Liste de tous les instruments joués par ce musicien
     
        @ManyToMany
        @JoinTable(name = "Musicians_Styles",
                joinColumns = @JoinColumn(name = "musician_id"),
                inverseJoinColumns = @JoinColumn(name = "style_id"))
        private List<Style> styles = new ArrayList<>();
     
        // un musicien peut être disponible dans plusieurs villes
        @ManyToMany
        @JoinTable(name = "Musicians_Towns",
                joinColumns = @JoinColumn(name = "musician_id"),
                inverseJoinColumns = @JoinColumn(name = "town_id"))
        private List<Town> towns = new ArrayList<>();
     
        @ManyToMany
        @JoinTable(name = "Musicians_MRMs",
                joinColumns = @JoinColumn(name = "musician_id"),
                inverseJoinColumns = @JoinColumn(name = "mrm_id"))
        private List<MRM> MRMs = new ArrayList<>(); // Liste de toutes les recherches de musiciens faites par ce musicien
     
        @ManyToMany
        @JoinTable(name = "Musicians_MRGs",
                joinColumns = @JoinColumn(name = "musician_id"),
                inverseJoinColumns = @JoinColumn(name = "mrg_id"))
        private List<MRG> MRGs = new ArrayList<>(); // Liste de toutes les recherches de groupes faites par ce musicien
     
     
        public Long getId() {
            return id;
        }
     
        public void setId(Long id) {
            this.id = id;
        }
     
        public String getSurName() {
            return surName;
        }
     
        public void setSurName(String surName) {
            this.surName = surName;
        }
     
        public String getLastName() {
            return lastName;
        }
     
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
     
        public String getFirstName() {
            return firstName;
        }
     
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
     
        public boolean getSex() {
            return sex;
        }
     
        public void setSex(boolean sex) {
            this.sex = sex;
        }
     
        public int getAge() {
            return age;
        }
     
        public void setAge(int age) {
            this.age = age;
        }
     
        public boolean isAvailable() {
            return available;
        }
     
        public void setAvailable(boolean available) {
            this.available = available;
        }
     
        public List<Instrument> getInstruments() {
            return instruments;
        }
     
        public void setInstruments(List<Instrument> instruments) {
            this.instruments = instruments;
        }
     
        public List<SubInstrument> getSubInstruments() {
            return subInstruments;
        }
     
        public void setSubInstruments(List<SubInstrument> subInstruments) {
            this.subInstruments = subInstruments;
        }
     
        public List<Style> getStyles() {
            return styles;
        }
     
        public void setStyles(List<Style> styles) {
            this.styles = styles;
        }
     
        public List<Town> getTowns() {
            return towns;
        }
     
        public void setTowns(List<Town> towns) {
            this.towns = towns;
        }
     
        public List<MRM> getMRMs() {
            return MRMs;
        }
     
        public void setMRMs(List<MRM> MRMs) {
            this.MRMs = MRMs;
        }
     
        public List<MRG> getMRGs() {
            return MRGs;
        }
     
        public void setMRGs(List<MRG> MRGs) {
            this.MRGs = MRGs;
        }
    }


    Entity Group:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
     
    package com.praline40.MeetZicker.Group;
     
    import com.praline40.MeetZicker.Concert.Concert;
    import com.praline40.MeetZicker.GRG.GRG;
    import com.praline40.MeetZicker.GRM.GRM;
    import com.praline40.MeetZicker.Instrument.Instrument;
    import com.praline40.MeetZicker.Musician.Musician;
    import com.praline40.MeetZicker.Style.Style;
    import com.praline40.MeetZicker.Town.Town;
     
    import javax.persistence.*;
    import java.util.ArrayList;
    import java.util.List;
     
    @Entity
    @Table(name="Groups")
    public class Group {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
     
        private String name;
     
        @ManyToMany
        @JoinTable(name = "Groups_Concerts",
                joinColumns = @JoinColumn(name = "group_id"),
                inverseJoinColumns = @JoinColumn(name = "concert_id"))
        private List<Concert> concerts = new ArrayList<>();
     
        /* Un groupe peut contenir plusieurs musiciens et un même musicien peut appartenir à plusieurs groupes */
        @ManyToMany
        @JoinTable(name = "Groups_Musicians",
                joinColumns = @JoinColumn(name = "group_id"),
                inverseJoinColumns = @JoinColumn(name = "musician_id"))
        private List<Musician> musicians = new ArrayList<>(); // Liste de tous les musiciens du groupe
     
        @ManyToMany
        @JoinTable(name = "Groups_Styles",
                joinColumns = @JoinColumn(name = "group_id"),
                inverseJoinColumns = @JoinColumn(name = "style_id"))
        private List<Style> styles = new ArrayList<>();
     
        @ManyToMany
        @JoinTable(name = "Groups_Instruments",
                joinColumns = @JoinColumn(name = "group_id"),
                inverseJoinColumns = @JoinColumn(name = "instrument_id"))
        private List<Instrument> instruments = new ArrayList<>();
     
        // Un groupe peut répéter dans plusieurs villes.
        @ManyToMany
        @JoinTable(name = "Groups_Towns",
                joinColumns = @JoinColumn(name = "group_id"),
                inverseJoinColumns = @JoinColumn(name = "town_id"))
        private List<Town> towns = new ArrayList<>();
     
        // Un groupe peut rechercher plusieurs musiciens
        @ManyToMany
        @JoinTable(name = "Groups_GRMs",
                joinColumns = @JoinColumn(name = "group_id"),
                inverseJoinColumns = @JoinColumn(name = "grm_id"))
        private List<GRM> GRMs = new ArrayList<>(); // Liste de toutes les recherches de musiciens faites par ce groupe
     
        @ManyToMany
        @JoinTable(name = "Groups_GRGs",
                joinColumns = @JoinColumn(name = "group_id"),
                inverseJoinColumns = @JoinColumn(name = "grg_id"))
        private List<GRG> GRGs = new ArrayList<>(); // Liste de toutes les recherches de groupes faites par ce groupe
     
     
        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;
        }
     
        public List<Concert> getConcerts() {
            return concerts;
        }
     
        public void setConcerts(List<Concert> concerts) {
            this.concerts = concerts;
        }
     
        public List<Musician> getMusicians() {
            return musicians;
        }
     
        public void setMusicians(List<Musician> musicians) {
            this.musicians = musicians;
        }
     
        public List<Style> getStyles() {
            return styles;
        }
     
        public void setStyles(List<Style> styles) {
            this.styles = styles;
        }
     
        public List<Instrument> getInstruments() {
            return instruments;
        }
     
        public void setInstruments(List<Instrument> instruments) {
            this.instruments = instruments;
        }
     
        public List<Town> getTowns() {
            return towns;
        }
     
        public void setTowns(List<Town> towns) {
            this.towns = towns;
        }
     
        public List<GRM> getGRMs() {
            return GRMs;
        }
     
        public void setGRMs(List<GRM> GRMs) {
            this.GRMs = GRMs;
        }
     
        public List<GRG> getGRGs() {
            return GRGs;
        }
     
        public void setGRGs(List<GRG> GRGs) {
            this.GRGs = GRGs;
        }
    }

  10. #10
    Membre émérite
    Homme Profil pro
    Ingénieur en génie logiciel
    Inscrit en
    Juin 2012
    Messages
    905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur en génie logiciel
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Juin 2012
    Messages : 905
    Points : 2 575
    Points
    2 575
    Par défaut
    tu as définir ta relation many to many de façon identique des deux côtés de la relation...

    tu dois avoir un owner side et un target side...
    regarde
    https://www.baeldung.com/jpa-many-to-many

    voir leur exemple

    dans une classe tu as
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    //student class
    @ManyToMany
    @JoinTable(
      name = "course_like", 
      joinColumns = @JoinColumn(name = "student_id"), 
      inverseJoinColumns = @JoinColumn(name = "course_id"))
    Set<Course> likedCourses;
    dans l'autre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    //course class
    @ManyToMany(mappedBy = "likedCourses")
    Set<Student> likes;

  11. #11
    Membre régulier
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juin 2011
    Messages
    258
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2011
    Messages : 258
    Points : 76
    Points
    76
    Par défaut
    Merci,

    J'ai remodifié mon code avec beaucoup de simplifications.

    J'ai toujours cette erreur lors d'un GET:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     
    2022-02-18 10:24:10.953  WARN 1 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: com.praline40.MeetZicker.Style.Style.musicians, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.praline40.MeetZicker.Style.Style.musicians, could not initialize proxy - no Session (through reference chain: org.springframework.hateoas.CollectionModel["_embedded"]->java.util.LinkedHashMap["styleList"]->java.util.ArrayList[0]->org.springframework.hateoas.EntityModel["content"]->com.praline40.MeetZicker.Style.Style["musicians"])]

    Nom : Screenshot from 2022-02-18 11-26-24.png
Affichages : 427
Taille : 44,5 Ko


    Musician:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
     
    package com.praline40.MeetZicker.Musician;
     
    import com.praline40.MeetZicker.Group.Group;
    import com.praline40.MeetZicker.MRG.MRG;
    import com.praline40.MeetZicker.MRM.MRM;
    import com.praline40.MeetZicker.Style.Style;
    import com.praline40.MeetZicker.SubInstrument.SubInstrument;
    import com.praline40.MeetZicker.Town.Town;
     
    import javax.persistence.*;
    import java.util.ArrayList;
    import java.util.List;
     
    @Entity
    @Table(name="Musicians")
    public class Musician {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String surName;
        private String lastName;
        private String firstName;
        private boolean sex;
        private int age;
        private boolean available; // le musicien affiche sa disponibilité
     
        @ManyToMany
        @JoinTable(name = "Musicians_SubInstruments",
                joinColumns = @JoinColumn(name = "musician_id"),
                inverseJoinColumns = @JoinColumn(name = "subInstrument_id"))
        private List<SubInstrument> subInstruments = new ArrayList<>(); // Liste de tous les instruments joués par ce musicien
     
        @ManyToMany(cascade = { CascadeType.ALL })
        @JoinTable(name = "Musicians_Styles",
                joinColumns = @JoinColumn(name = "musician_id"),
                inverseJoinColumns = @JoinColumn(name = "style_id"))
        private List<Style> styles = new ArrayList<>();
     
        // un musicien peut être disponible dans plusieurs villes
        @ManyToMany
        @JoinTable(name = "Musicians_Towns",
                joinColumns = @JoinColumn(name = "musician_id"),
                inverseJoinColumns = @JoinColumn(name = "town_id"))
        private List<Town> towns = new ArrayList<>();
     
        @ManyToMany(mappedBy = "musicians")
        private List<Group> groups= new ArrayList<>(); // Liste de tous les groupes du musicien
     
        @OneToMany(mappedBy = "musician", cascade = CascadeType.ALL)
        private List<MRG> MRGs;
     
        @OneToMany(mappedBy = "musician", cascade = CascadeType.ALL)
        private List<MRM> MRMs;
     
        public Long getId() {
            return id;
        }
     
        public void setId(Long id) {
            this.id = id;
        }
     
        public String getSurName() {
            return surName;
        }
     
        public void setSurName(String surName) {
            this.surName = surName;
        }
     
        public String getLastName() {
            return lastName;
        }
     
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
     
        public String getFirstName() {
            return firstName;
        }
     
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
     
        public boolean getSex() {
            return sex;
        }
     
        public void setSex(boolean sex) {
            this.sex = sex;
        }
     
        public int getAge() {
            return age;
        }
     
        public void setAge(int age) {
            this.age = age;
        }
     
        public boolean isAvailable() {
            return available;
        }
     
        public void setAvailable(boolean available) {
            this.available = available;
        }
     
        public List<SubInstrument> getSubInstruments() {
            return subInstruments;
        }
     
        public void setSubInstruments(List<SubInstrument> subInstruments) {
            this.subInstruments = subInstruments;
        }
     
        public List<Style> getStyles() {
            return styles;
        }
     
        public void setStyles(List<Style> styles) {
            this.styles = styles;
        }
     
        public List<Town> getTowns() {
            return towns;
        }
     
        public void setTowns(List<Town> towns) {
            this.towns = towns;
        }
     
        public List<MRM> getMRMs() {
            return MRMs;
        }
     
        public void setMRMs(List<MRM> MRMs) {
            this.MRMs = MRMs;
        }
     
        public List<MRG> getMRGs() {
            return MRGs;
        }
     
        public void setMRGs(List<MRG> MRGs) {
            this.MRGs = MRGs;
        }
    }


    Style:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
     
     
    package com.praline40.MeetZicker.Style;
     
    import com.praline40.MeetZicker.Group.Group;
    import com.praline40.MeetZicker.Musician.Musician;
     
    import javax.persistence.*;
    import java.util.ArrayList;
    import java.util.List;
     
    @Entity
    @Table(name="Styles")
    public class Style {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
     
        private String name;
     
        @ManyToMany(mappedBy = "styles")
        private List<Musician> musicians = new ArrayList<>();
     
        @ManyToMany(mappedBy = "styles")
        private List<Group> groups = new ArrayList<>();
     
        public Style() {
        }
     
        public Style(Long id, String name, List<Musician> musicians, List<Group> groups) {
            this.id = id;
            this.name = name;
            this.musicians = musicians;
            this.groups = groups;
        }
     
        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;
        }
     
        public List<Musician> getMusicians() {
            return musicians;
        }
     
        public void setMusicians(List<Musician> musicians) {
            this.musicians = musicians;
        }
     
        public List<Group> getGroups() {
            return groups;
        }
     
        public void setGroups(List<Group> groups) {
            this.groups = groups;
        }
     
     
    }

    Après je n'ai pas fait de set up de database je n'ai que les entités dans mon code, pas de requête de création de bdd. Peut-être que j'ai loupé une étape.

  12. #12
    Membre émérite
    Homme Profil pro
    Ingénieur en génie logiciel
    Inscrit en
    Juin 2012
    Messages
    905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur en génie logiciel
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Juin 2012
    Messages : 905
    Points : 2 575
    Points
    2 575
    Par défaut
    tu as plusieurs many to many... il faut que tu fasses la correction pour chacun d'eux...

    ce qui arrive actuellement c'est que tu essaies de charger les styles et le orm va chercher aussi les musiciens qui y sont associés

  13. #13
    Membre régulier
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juin 2011
    Messages
    258
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2011
    Messages : 258
    Points : 76
    Points
    76
    Par défaut
    Je ne vois pas où est le soucis dans mon code j'ai bien un owner et un target side avec deux écritures distinctes.

    Dans Musician:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    @ManyToMany(cascade = { CascadeType.ALL })
        @JoinTable(name = "Musicians_Styles",
                joinColumns = @JoinColumn(name = "musician_id"),
                inverseJoinColumns = @JoinColumn(name = "style_id"))
        private List<Style> styles = new ArrayList<>();
    Dans Style:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        @ManyToMany(mappedBy = "styles")
        private List<Musician> musicians = new ArrayList<>();
    J'ai regardé par là mais rien n'y fait... https://stackoverflow.com/questions/...ection-of-role

  14. #14
    Membre régulier
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juin 2011
    Messages
    258
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2011
    Messages : 258
    Points : 76
    Points
    76
    Par défaut
    Un avis, un conseil ?

Discussions similaires

  1. Réponses: 0
    Dernier message: 16/07/2021, 01h50
  2. Réponses: 1
    Dernier message: 21/10/2020, 17h40
  3. Réponses: 0
    Dernier message: 13/06/2014, 10h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo