Search code examples
androidodata4j

odata4j requests metadata too many times


I use the odata4j library to access a WCF Data Service.

This is how I call a Service Method from my Android code:

 OQueryRequest<OEntity> l = consumer.getEntities("GetDataList")
    .custom("dataId", String.format("'%s'", actualData.ID))
    .orderBy("Name").skip(0).top(200);

I checked it with WireShark, and I see that every method call is preceded with 2 calls of metadata information request:

enter image description here

Why? Are they essential? The metadata information is quite heavy, it shouldn't request is every time (not to mention 2 times).

What should I do to prevent odata4j from requesting metadata information so many times?


Solution

  • I found in the source code where the 'extra' request happens (in odata4j/odata4j-core/src/main/java/org/odata4j/consumer/AbstractODataConsumer.java ):

    @Override
    public EdmEntitySet findEdmEntitySet(String entitySetName) {
      EdmEntitySet rt = super.findEdmEntitySet(entitySetName);
      if (rt == null && delegate != EdmDataServices.EMPTY) {
        refreshDelegate();
        rt = super.findEdmEntitySet(entitySetName);
      }
      return rt;
    }
    

    It seems that if the entity set can't be found, the consumer creates an extra roundtrip to the server to get the metadata again (by calling refreshDelegate()):

    private void refreshDelegate() {
      ODataClientRequest request = ODataClientRequest.get(AbstractODataConsumer.this.getServiceRootUri() + "$metadata");
      try {
        delegate = AbstractODataConsumer.this.getClient().getMetadata(request);
      } catch (ODataProducerException e) {
        // to support services that do not expose metadata information
        delegate = EdmDataServices.EMPTY;
      }
    }
    

    I don't quite understand why: maybe it assumes that the server has changed and a new version of the metadata is available so it tries again.

    If it fails then it tries to find a function with the given name.

    Personally I don't consider this very effective unless the server side is so volatile that it changes between calls.

    So, if you have no changing metadata on the server, it is safe to remove the check for the entitySet and let it return as a null:

    @Override
    public EdmEntitySet findEdmEntitySet(String entitySetName) {
      EdmEntitySet rt = super.findEdmEntitySet(entitySetName);
      //if (rt == null && delegate != EdmDataServices.EMPTY) {
      //  refreshDelegate();
      //  rt = super.findEdmEntitySet(entitySetName);
      //}
      return rt; //if it is null, then the search for a function will commence
    }