title: Spring REST API method for update object doesn't retrieve existing sub-objects
body: <p>I have a Spring Boot + Hibernate + mySQL based REST API with the usual methods for CRUD operations and data retrieval. There are several many to many relationships in the model, I'll show the relevant classes for my problem:</p>
  
  <h3>Pectest.java</h3>
  
  <pre><code>@Entity
  @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
  @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="idtest")
  public class Pectest {
      @Id
      @GeneratedValue
      @Column(name="idtest")
      private int idtest=-1;
      private String testname;
      private String testdescription;
      @ManyToOne(fetch=FetchType.LAZY)
      @JoinColumn(name="idtesttype")
      private Testtype testtype;
      @ManyToOne(fetch=FetchType.LAZY)
      @JoinColumn(name="iddatatype")
      private Datatype datatype;
      private String testurl;
      private Date datecreated;
      private Date lastupdated;
  
      @ManyToMany(cascade = { 
              CascadeType.PERSIST, 
              CascadeType.MERGE
          })
      @JoinTable(name = "test_checks_requisite",
              joinColumns = @JoinColumn(name = "test_idtest"),
              inverseJoinColumns = @JoinColumn(name = "requisite_idrequisite")
          )
      private Set&lt;Requisite&gt; requisites = new HashSet&lt;Requisite&gt;();
  
  // Getters and setters
  [...]
  }
  </code></pre>
  
  <h3>Requisite.java</h3>
  
  <pre><code>@Entity
  @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
  @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="idrequisite")
  public class Requisite {
      @Id
      @GeneratedValue //(strategy=GenerationType.IDENTITY)
      @Column(name="idrequisite")
      private int idrequisite;
      private String Name;
      private String Title;
      private String Description;
      @ManyToOne(cascade = {CascadeType.PERSIST}, fetch=FetchType.LAZY)
      @JoinColumn(name="functionality_idfunctionality")
      private Functionality functionality; 
  
      @ManyToMany(mappedBy="requisites")
      private Set&lt;Pectest&gt; tests = new HashSet&lt;Pectest&gt;();
  
  // Getters and setters
  [...]
  }
  </code></pre>
  
  <p>The GET methods for both are working as intended, correctly retrieving the <strong>Requisite</strong> list of a given <strong>Pectest</strong>. However, when I try to update an existing <strong>Pectest</strong> by calling the corresponding API entry point I found that it does not fetch the existing requisites in the JSON from the DB, giving them an idrequisite value of 0 (as shown below). Therefore, Hibernate "decides" that they should be inserted as new. It fails due to a Unique constraint in the DB, but the problem is that they shouldn't be inserted at all.</p>
  
  <p>The updating process of a <strong>Pectest</strong> object can involve (besides the obvious name, description, etc, modifications) adding more <strong>Requisite</strong> elements to its list, but those elements will never be updated themselves at that point.</p>
  
  <p>Here goes all the extra information:</p>
  
  <h3>Example of JSON data passed to the PUT method of the API</h3>
  
  <pre><code>    {
    "idtest": 9,
    "testtype": { "idTestType": 5, "testTypeName": "Manual" },
    "datatype": null,
    "requisites": [
      {
        "idrequisite": 2,
        "functionality": {
          "idfunctionality": 1002,
          "functionalityName": "Data Access OPC-UA",
          "parentFunctionality": {
            "idfunctionality": 1000,
            "functionalityName": "OPC-UA",
            "parentFunctionality": null,
            "childrenFunctionalities": [
              {
                "idfunctionality": 1006,
                "functionalityName": "Alarmas OPC-UA",
                "parentFunctionality": 1000,
                "childrenFunctionalities": [],
                "description": "Para el tratamiento de las Alarmas del producto BR, se utilizará el tipo propietario AlarmEventType, heredado del tipo básico de alarmas OffNormalAlarmType definido por la especificación OPC UA (Part 9). El Servidor OPC-UA deberá generar un nodo AlarmEventType para cada una de las alarmas definidas en el proyecto en concreto del producto BR (hasta 8192 alarmas distintas)."
              },
              {
                "idfunctionality": 1001,
                "functionalityName": "Atributos OPC-UA",
                "parentFunctionality": 1000,
                "childrenFunctionalities": [],
                "description": "Atributos"
              },
              1002,
              {
                "idfunctionality": 1009,
                "functionalityName": "Device Integration OPC-UA",
                "parentFunctionality": 1000,
                "childrenFunctionalities": [
                  {
                    "idfunctionality": 1011,
                    "functionalityName": "Tipo FieldDeviceType OPC-UA",
                    "parentFunctionality": 1009,
                    "childrenFunctionalities": [],
                    "description": "A partir del tipo estándar DeviceType definido por “OPC UA Device Integration” se crea el tipo propietario FieldDeviceType para representar e identificar al producto BR."
                  }
                ],
                "description": "A partir del tipo estándar DeviceType definido por “OPC UA Device Integration” se crea el tipo propietario FieldDeviceType para representar e identificar al producto BR."
              },
              {
                "idfunctionality": 1012,
                "functionalityName": "Global Discovery Server OPC-UA",
                "parentFunctionality": 1000,
                "childrenFunctionalities": [],
                "description": "El servidor OPC UA implementará el “Global Certificate Management Server Facet” para comunicarse con el GDS "
              },
              {
                "idfunctionality": 1008,
                "functionalityName": "Historical Access OPC-UA",
                "parentFunctionality": 1000,
                "childrenFunctionalities": [],
                "description": "Esta funcionalidad es resuelta íntegramente por el Servidor OPC-UA, ya que el FW embebido no ofrece soporte para ella."
              },
              {
                "idfunctionality": 1007,
                "functionalityName": "Monitoring &amp; Subscription OPC-UA",
                "parentFunctionality": 1000,
                "childrenFunctionalities": [],
                "description": "Subscripciones para visualización de datos desde un cliente OPC-UA"
              },
              {
                "idfunctionality": 1010,
                "functionalityName": "Seguridad OPC-UA",
                "parentFunctionality": 1000,
                "childrenFunctionalities": [],
                "description": "El servidor OPC-UA debe implementar una serie de medidas de seguridad para garantizar la confidencialidad de la información."
              }
            ],
            "description": "OPC-UA Server"
          },
          "childrenFunctionalities": [
            {
              "idfunctionality": 1004,
              "functionalityName": "AnalogType OPC-UA",
              "parentFunctionality": 1002,
              "childrenFunctionalities": [],
              "description": "Este tipo propietario se utiliza para los nodos OPC-UA de variables no booleanas del producto BR que no sean parámetros."
            },
            {
              "idfunctionality": 1003,
              "functionalityName": "DigitalType OPC-UA",
              "parentFunctionality": 1002,
              "childrenFunctionalities": [],
              "description": "Tipo propietario de datos booleanos servido por OPC-UA, que no sean parámetros."
            },
            {
              "idfunctionality": 1005,
              "functionalityName": "ParameterType OPC-UA",
              "parentFunctionality": 1002,
              "childrenFunctionalities": [],
              "description": "Este tipo propietario se utiliza para los nodos OPC-UA de variables del producto BR que estén identificadas como parámetros. El servidor OPC-UA debe identificar dichas variables del producto BR como aquellas que tengan atributo ParamGID. "
            }
          ],
          "description": "Se ofrecerá acceso a las variables exportadas por el FW de la CPU del producto BR a través de tres tipos propietarios de nodos: DigitalType, AnalogType y ParameterType"
        },
        "name": "REQ-0001",
        "description": "Se ofrece acceso a variables digitales a través de este tipo de nodo",
        "title": "Digital Type"
      },
      {
        "idrequisite": 4,
        "functionality": 1002,
        "name": "REQ-0003",
        "description": "Se ofrece acceso a parámetros a través de este tipo de nodo",
        "title": "Parameter Type"
      },
      {
        "idrequisite": 3,
        "functionality": 1002,
        "name": "REQ-0002",
        "description": "Se ofrece acceso a variables analógicas a través de este tipo de nodo",
        "title": "Analog Type"
      }
    ],
    "testDescription": "El servidor es capaz de devolver correctamente todos los tipos de dato.",
    "testURL": "",
    "testName": "Lectura de DataTypes",
    "dateCreated": "09-05-2018 08:57:27",
    "lastUpdated": "09-05-2018 08:57:27"
  }
  </code></pre>
  
  <h3>PecTestController.java</h3>
  
  <pre><code>[...]
  @PostMapping(path="/test", produces= MediaType.APPLICATION_JSON_VALUE)
      public Pectest createOrUpdateTest(@Valid @RequestBody Pectest newtest) {
          try {
              System.out.println("Create or update Test: " + objectmapper.writeValueAsString(newtest));
          } catch (JsonProcessingException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
  
          return testService.saveOrUpdate(newtest);
      }
  </code></pre>
  
  <h3>Console output (formatted)</h3>
  
  <pre><code>  {
        "idtest": 9,
        "testtype": { "idTestType": 5, "testTypeName": "Manual" },
        "datatype": null,
        "requisites": [
          {
            "idrequisite": 0,
            "functionality": {
              "idfunctionality": 0,
              "functionalityName": "Data Access OPC-UA",
              "parentFunctionality": {
                "idfunctionality": 0,
                "functionalityName": "OPC-UA",
                "parentFunctionality": null,
                "childrenFunctionalities": [
                  {
                    "idfunctionality": 0,
                    "functionalityName": "Device Integration OPC-UA",
                    "parentFunctionality": 0,
                    "childrenFunctionalities": [
                      {
                        "idfunctionality": 0,
                        "functionalityName": "Tipo FieldDeviceType OPC-UA",
                        "parentFunctionality": 0,
                        "childrenFunctionalities": [],
                        "description": "A partir del tipo estándar DeviceType definido por “OPC UA Device Integration” se crea el tipo propietario FieldDeviceType para representar e identificar al producto BR."
                      }
                    ],
                    "description": "A partir del tipo estándar DeviceType definido por “OPC UA Device Integration” se crea el tipo propietario FieldDeviceType para representar e identificar al producto BR."
                  },
                  {
                    "idfunctionality": 0,
                    "functionalityName": "Historical Access OPC-UA",
                    "parentFunctionality": 0,
                    "childrenFunctionalities": [],
                    "description": "Esta funcionalidad es resuelta íntegramente por el Servidor OPC-UA, ya que el FW embebido no ofrece soporte para ella."
                  },
                  {
                    "idfunctionality": 0,
                    "functionalityName": "Atributos OPC-UA",
                    "parentFunctionality": 0,
                    "childrenFunctionalities": [],
                    "description": "Atributos"
                  },
                  {
                    "idfunctionality": 0,
                    "functionalityName": "Alarmas OPC-UA",
                    "parentFunctionality": 0,
                    "childrenFunctionalities": [],
                    "description": "Para el tratamiento de las Alarmas del producto BR, se utilizará el tipo propietario AlarmEventType, heredado del tipo básico de alarmas OffNormalAlarmType definido por la especificación OPC UA (Part 9). El Servidor OPC-UA deberá generar un nodo AlarmEventType para cada una de las alarmas definidas en el proyecto en concreto del producto BR (hasta 8192 alarmas distintas)."
                  },
                  0,
                  {
                    "idfunctionality": 0,
                    "functionalityName": "Monitoring &amp; Subscription OPC-UA",
                    "parentFunctionality": 0,
                    "childrenFunctionalities": [],
                    "description": "Subscripciones para visualización de datos desde un cliente OPC-UA"
                  },
                  {
                    "idfunctionality": 0,
                    "functionalityName": "Seguridad OPC-UA",
                    "parentFunctionality": 0,
                    "childrenFunctionalities": [],
                    "description": "El servidor OPC-UA debe implementar una serie de medidas de seguridad para garantizar la confidencialidad de la información."
                  },
                  {
                    "idfunctionality": 0,
                    "functionalityName": "Global Discovery Server OPC-UA",
                    "parentFunctionality": 0,
                    "childrenFunctionalities": [],
                    "description": "El servidor OPC UA implementará el “Global Certificate Management Server Facet” para comunicarse con el GDS "
                  }
                ],
                "description": "OPC-UA Server"
              },
              "childrenFunctionalities": [
                {
                  "idfunctionality": 0,
                  "functionalityName": "ParameterType OPC-UA",
                  "parentFunctionality": 0,
                  "childrenFunctionalities": [],
                  "description": "Este tipo propietario se utiliza para los nodos OPC-UA de variables del producto BR que estén identificadas como parámetros. El servidor OPC-UA debe identificar dichas variables del producto BR como aquellas que tengan atributo ParamGID. "
                },
                {
                  "idfunctionality": 0,
                  "functionalityName": "DigitalType OPC-UA",
                  "parentFunctionality": 0,
                  "childrenFunctionalities": [],
                  "description": "Tipo propietario de datos booleanos servido por OPC-UA, que no sean parámetros."
                },
                {
                  "idfunctionality": 0,
                  "functionalityName": "AnalogType OPC-UA",
                  "parentFunctionality": 0,
                  "childrenFunctionalities": [],
                  "description": "Este tipo propietario se utiliza para los nodos OPC-UA de variables no booleanas del producto BR que no sean parámetros."
                }
              ],
              "description": "Se ofrecerá acceso a las variables exportadas por el FW de la CPU del producto BR a través de tres tipos propietarios de nodos: DigitalType, AnalogType y ParameterType"
            },
            "name": "REQ-0003",
            "description": "Se ofrece acceso a parámetros a través de este tipo de nodo",
            "title": "Parameter Type"
          },
          {
            "idrequisite": 0,
            "functionality": 0,
            "name": "REQ-0002",
            "description": "Se ofrece acceso a variables analógicas a través de este tipo de nodo",
            "title": "Analog Type"
          },
          {
            "idrequisite": 0,
            "functionality": 0,
            "name": "REQ-0001",
            "description": "Se ofrece acceso a variables digitales a través de este tipo de nodo",
            "title": "Digital Type"
          }
        ],
        "testDescription": "El servidor es capaz de devolver correctamente todos los tipos de dato.",
        "testURL": "",
        "testName": "Lectura de DataTypes",
        "dateCreated": null,
        "lastUpdated": null
      }
  </code></pre>
  
  <p>As you can see, the id's for all the nested objects are zero. Why doesn't Hibernate try to retrieve those elements? Is there some annotation missing in the model? </p>
  
  <p>As a workaround, I'm thinking about ignoring the whole list of <strong>Requisite</strong> objects when updating a <strong>Pectest</strong> and provide an individual entry point in the API for adding requisites to a test that will be called separately.</p>
  
  <p>I checked <a href="https://stackoverflow.com/questions/1188410/hibernate-manytomany-with-join-table-problems-on-update">this</a> thread, which points to <a href="http://www.java2s.com/Code/Java/JPA/ManyToManyJoinedTable.htm" rel="nofollow noreferrer">this</a> example, but couldn't find the solution. </p>