spring-projects / spring-projects/spring-data-rest

Map field with String key type not set when POST'ing parent resource [DATAREST-1441]

Open
#1,801 1 comment 1 reaction 1 assignee View on GitHub

@odrotbohm is already working on this.

Since Dec 31, 2020.

type: bug
Dominant language
Java
Stars
958
Forks
568
PR merge metrics
No merged PRs in 30d

Description

Armel Soro opened DATAREST-1441 and commented

Hi there!

When trying to POST a new resource containing a Map<String, Item> field, I noticed that this field always remains empty and is never updated.

This may be related to DATAREST-960, except that I'm not using URIs.

For the purpose of this issue, I've created a sample test reproduction project, with an integration test that is not passing: https://github.com/rm3l/sdr-issue-map-unmarshalling

For example, I have the following rather simple domain objects:

= Order.java =

@Entity
public class Order extends AbstractBaseJpaEntity {

  @Basic
  @Access(AccessType.PROPERTY) 
  @com.fasterxml.jackson.annotation.JsonProperty("internalId")
  private Long internalId;
  
  @Basic
  @Access(AccessType.PROPERTY)   
  @com.fasterxml.jackson.annotation.JsonProperty("name")
  private String name;

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
  @JoinTable(name = "order_item_map")
  @Access(AccessType.PROPERTY)
  @com.fasterxml.jackson.annotation.JsonProperty("itemMap")
  private Map<String, Item> itemMap;

  //..accessors omitted for brevity
}

 = Item.java =

@Entity
public class Item extends AbstractBaseJpaEntity { 

  @Basic(optional = false)
  @Access(AccessType.PROPERTY)
  @com.fasterxml.jackson.annotation.JsonProperty("itemName")
  private String itemName;
 
 @Basic
 @Access(AccessType.PROPERTY)   
 @com.fasterxml.jackson.annotation.JsonProperty("myIntegerAttribute")
 private Integer myIntegerAttribute;

 //..accessors omitted for brevity
}

Now I'm trying to create a new Order, along with its Items:

POST /Order -d '
{
  "internalId" : 1000,
  "name" : "my order #1",
  "itemMap" : { 
     "key_1" : {"itemName" : "my item #1", "myIntegerAttribute": 11, "fake_attr" : "does not exist"},
     "key_2" : {"itemName" : "my item #2", "myIntegerAttribute": 12}
  }
}
'

The request above returns :

{
      "idDb" : 2,
      "internalId" : 1000,
      "name" : "my order #1",
      "_embedded" : {
        "itemMap" : { }
      },
      "_links" : {
        "self" : {
          "href" : "http://localhost/Order/2"
        },
        "Order" : {
          "href" : "http://localhost/Order/2"
        },
        "itemMap" : {
          "href" : "http://localhost/Order/2/itemMap"
        }
      }
    }

And following the itemMap link returns:

{
  "content" : { }
}

Perhaps I'm missing something here, but this exact request used to work at least when I was running SpringBoot 1.5.7. 

Notes

  • GET'ing an instance already in the data store does work, i.e., following the itemMap link works; and I don't know if this is the expected behavior, but I noticed that it is also serialized as "_embedded" in the parent resource body. For example:
GET /Order/1

{                                                              
      "idDb" : 1,                                                  
      "internalId" : 9999,                                                                                                                                                                                                        
      "name" : "my test order",
      "_embedded" : {                                                                                                                                                                                                             
        "itemMap" : {                                                                                                                                                                                                             
          "first" : {
            "idDb" : 1,   
            "itemName" : "my test order item",                                                                                                                                                                                    
            "myIntegerAttribute" : 333       
          }                                                                                                                                                                                                                       
        }                                                                           
      },                                     
      "_links" : {                      
        "self" : {   
          "href" : "http:// localhost/Order/1"        
        },                        
        "Order" : {                                                                                                                                                                                                               
          "href" : "http://localhost/Order/1"
        },                                                                                                                                               
        "itemMap" : {                                                                                                                                                                                                             
          "href" : "http://localhost/Order/1/itemMap"                                                                                                 
        }                                                                                                                                  
      }                                                                                                                      
    }

Following the itemMap link:

GET /Order/1/itemMap

{                                           
      "content" : {                                   
        "first" : {
          "idDb" : 1,
          "itemName" : "my test order item",                                                                    
          "myIntegerAttribute" : 333,                                     
          "_links" : {
            "self" : {
              "href" : "http://localhost/Item/1"
            },
            "Item" : {
              "href" : "http://localhost/Item/1"
            }
          }
        }
      }
    }
  • Using an @ElementCollection association for the Map or not exporting the ItemRepository (using @RepositoryRestResource(exported=false)) also works, but, as perhaps expected, I no longer have the link to the itemMap

Thanks. 


Affects: 3.2 GA (Moore)

Reference URL: https://github.com/rm3l/sdr-issue-map-unmarshalling

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.