user3897311
user3897311

Reputation: 11

Specifying entity type using Apache Olingo

I am using Apache Olingo v4 java library in my project and it works great. Thanks!

I am having issues calling one particular endpoint -

https://learn.microsoft.com/en-us/dynamics365/customer-engagement/web-api/merge?view=dynamics-ce-odata-9

ISSUE : Cannot specify entity type in request. Cannot figure out if this has to be passed in as an annotation or what. I tried passing it in as a param but Library then appends its type as string param instead.

Expected request body to contain :

    "@odata.type": "Microsoft.Dynamics.CRM.account"

Actual request body contain :

    "@[email protected]": "String", 
    "@odata.type": "Microsoft.Dynamics.CRM.account"

The above request is causing exception inside crm since they do not expect this param.

An error occurred while validating input parameters: Microsoft.OData.ODataException: Does not support untyped value in non-open type.
  at System.Web.OData.Formatter.Deserialization.DeserializationHelpers.ApplyProperty(ODataProperty property, IEdmStructuredTypeReference resourceType, Object resource, ODataDeserializerProvider deserializerProvider, ODataDeserializerContext readContext)
  at System.Web.OData.Formatter.Deserialization.ODataResourceDeserializer.ApplyStructuralProperties(Object resource, ODataResourceWrapper resourceWrapper, IEdmStructuredTypeReference structuredType, ODataDeserializerContext readContext)
  at Microsoft.Crm.Extensibility.OData.CrmODataEntityDeserializer.ApplyStructuralProperties(Object resource, ODataResourceWrapper resourceWrapper, IEdmStructuredTypeReference structuredType, ODataDeserializerContext readContext)
  at System.Web.OData.Formatter.Deserialization.ODataResourceDeserializer.ReadResource(ODataResourceWrapper resourceWrapper, IEdmStructuredTypeReference structuredType, ODataDeserializerContext readContext)
  at Microsoft.Crm.Extensibility.OData.CrmODataActionPayloadDeserializer.ReadEntry(ODataDeserializerContext readContext, ODataParameterReader reader, IEdmOperationParameter parameter)
  at Microsoft.Crm.Extensibility.OData.CrmODataActionPayloadDeserializer.Read(ODataMessageReader messageReader, Type type, ODataDeserializerContext readContext)
  at System.Web.OData.Formatter.ODataMediaTypeFormatter.ReadFromStream(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger) [HTTP/1.1 400 Bad Request]

I have tried appending annotations to the object but those do not end up in request body.

For reference, following request body works using postman (plain old http client) :

{
    "Target": {
        "accountid": "b68c98c3-f339-e811-eeee-000d3a137a33",
        "@odata.type": "Microsoft.Dynamics.CRM.account"
    },
    "Subordinate": {
        "accountid": "f89a8c95-2353-e811-wwww-000d3a137896",
        "@odata.type": "Microsoft.Dynamics.CRM.account"
    },
    "UpdateContent": {
        "websiteurl": "testdata.com",
        "@odata.type": "Microsoft.Dynamics.CRM.account"
    },
    "PerformParentingChecks": "false"
} 

Thanks in advance for taking time to help me.

Upvotes: 0

Views: 706

Answers (1)

Paul H.
Paul H.

Reputation: 1074

Using Olingo client library could be chatty when trying to use the "type" system. Please check out code snippet below in groovy to see if it is helpful:

static AbstractODataInvokeRequest buildMergeRequest(ODataClient client, URI mergeUri,
        String targetLeadIdStr, String subLeadIdStr) {
    Map<String, ClientValue> params = [:]
    params.put("Target", buildEntityIdComplex(client, "leadid", targetLeadIdStr))
    params.put("Subordinate", buildEntityIdComplex(client, "leadid", subLeadIdStr))
    params.put("UpdateContent", buildEntityIdComplex(client, "leadid", "00000000-0000-0000-0000-000000000000"))
    params.put("PerformParentingChecks", client.getObjectFactory().newPrimitiveValueBuilder().buildBoolean(false))

    AbstractODataInvokeRequest funcReq =
            client.getInvokeRequestFactory().getActionInvokeRequest(mergeUri, ODataError.class, params)
                    .addCustomHeader("Authorization", "Bearer ${accessToken}")
    funcReq.setFormat(ContentType.JSON_NO_METADATA)
    return funcReq;
}

static ClientComplexValue buildEntityIdComplex(ODataClient client, String entityIdName, String entityIdValStr) {
    ClientComplexValue targetLeadId = client.getObjectFactory().
            newComplexValue("Microsoft.Dynamics.CRM.lead")
    targetLeadId.add(client.getObjectFactory().newPrimitiveProperty(entityIdName,
            client.getObjectFactory().newPrimitiveValueBuilder().buildGuid(buildKey(entityIdValStr))))
    targetLeadId.add(client.getObjectFactory().newPrimitiveProperty("@odata.type",
            client.getObjectFactory().newPrimitiveValueBuilder().buildString("#Microsoft.Dynamics.CRM.lead")))
    return targetLeadId
}

Noticed that:

  1. funcReq.setFormat(ContentType.JSON_NO_METADATA) to indicate JSON only format to send to server.
  2. From groovy to java, Intellij has a menu item to do that. Or you can manually add ";" and type most of the time.

Upvotes: 1

Related Questions