crnk-project / crnk-framework

JSON API library for Java
Apache License 2.0
289 stars 154 forks source link

OperationsClient posting null values for postable=false attributes #679

Open ryan13mt opened 4 years ago

ryan13mt commented 4 years ago

We are using crnk-client in an Api gateway to help clients create multiple resources in one api call.

When using client.getRepositoryForType(Person.class).create(person), this works perfectly.

But we have some resources that can be grouped together using jsonApiPatch approach. So for this i was trying to use the OperationsClient to add multiple resources together and executing one call.

This is throwing an issue where on the servlet side we have CrnkProperties.RESOURCE_FIELD_IMMUTABLE_WRITE_BEHAVIOR = 'FAIL'.

This is throwing "field 'person.status' cannot be accessed for POST" because the OperationsClient is sending it as null and the attribute is marked with @JsonApiField(postable = false).

We cannot change the Crnk property due to business requirements. I tried setting the ObjectMapper with objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL) but it seems to be ignored by the OperationsClient. Issue doesnt come up when attributes are marked with @JsonApiField(postable = false, readable = false).

To try and circumvent this issue, i tried to also use this: Resource personResource = new Resource(); personResource .setType("person"); personResource .setAttributes(objectMapper.convertValue(person, Map.class)); createPersonCall.add(HttpMethod.POST, personResource );

This will create a resource of type 'Person' and add only the attributes that are not null. But a problem comes up from QuerySpec:367 "must specify resourceType if io.crnk.core.engine.document.Resource is used" when i am clearly stating what resourceType this object is.

These are 2 unrelated issues but they are stopping us from grouping together resource creation.

remmeier commented 4 years ago

the issue likely comes from ResourceMapper:

 if (!isIgnored(field, queryContext) && field.getAccess().isReadable()) {

This line is slightly wrong. On the client side is should make use of the used method like isPostable or isPatchable if the method is used in that context. The used HttpMethod could be added and passed along to DocumentMapper.toDocument with DocumentMappingConfig.