elasticsearch-java icon indicating copy to clipboard operation
elasticsearch-java copied to clipboard

Converting a request/response back to its builder

Open fredy-scs opened this issue 3 years ago • 6 comments

I am trying to implement a generic deep pagination function that takes a SearchRequest, creates a point-in-time and then paginates through all the values using search_after.

This requires modifying the search request I am given to include the PIT and set the search_after field correctly. However, using the new client, I am unable to modify an existing request due to all data being immutable and all mutability being contained within the corresponding builder classes.

A solution to this problem could be adding a generated method that creates a builder from the values contained within the object. Alternatively, a new constructor could be added to the builder classes that take a constructed object and initialize their values from the object.

fredy-scs avatar Jan 04 '22 13:01 fredy-scs

Thanks for the feedback @fredy-scs. This is indeed something we have considered but haven't implemented yet. I'll make sure it's listed explicitely on the roadmap.

swallez avatar Jan 04 '22 13:01 swallez

Aha, that's the problems I've faced too. Please notice me if it is solved.

Link3750 avatar Feb 10 '22 09:02 Link3750

this is the workaround I have so far:

  public static <T extends JsonpSerializable, B extends ObjectBuilderBase> B toObjectBuilder(
      T obj,
      Supplier<B> createBuilder,
      Predicate<String> fieldFilter) {
    B builder = createBuilder.get();
    Class<?> objClass = obj.getClass();
    Class<?> builderClass = builder.getClass();

    for (Method method : objClass.getMethods()) {
      if (fieldFilter.test(method.getName()) && method.getParameterTypes().length == 0 &&
          !Void.class.equals(method.getReturnType())) {
        // look at public, no parameter, not void return type methods. likely field accessors
        // try look for a corresponding builder method
        Method builderMethod;

        try {
          builderMethod = builderClass.getMethod(method.getName(), method.getReturnType());
        } catch (NoSuchMethodException e) {
          // the corresponding method does not exist in builder, skip
          continue;
        }

        try {
          // see if this is part of an union field
          Method kindMethod = objClass.getMethod("is" + StringUtils.capitalize(method.getName()));
          if (kindMethod.getReturnType().equals(boolean.class)) {
            if (!(boolean) kindMethod.invoke(obj)) {
              // a union kind, and the current value is not this kind
              continue;
            }
          }
        } catch (NoSuchMethodException e) {
          // not a union field
        } catch (IllegalAccessException | InvocationTargetException e) {
          throw new IllegalStateException("Unable to convert to builder.", e);
        }

        try {
          builderMethod.invoke(builder, method.invoke(obj));
        } catch (IllegalAccessException | InvocationTargetException e) {
          throw new IllegalStateException("Unable to convert to builder.", e);
        }
      }
    }

    return builder;
  }

visualage avatar Mar 15 '22 02:03 visualage

We have the same problem, hope it can come soon!

jerryguowei avatar Mar 16 '22 00:03 jerryguowei

any news on this one?

sothawo avatar Dec 10 '22 17:12 sothawo

Was this abandoned? Would really like to see this functionality added.

I have a similar situation where I would like one part of my code to build the parts of the query that are context specific and have another part of my code "append" additional conditions to the query that are common to all requests. In my case it would be fields used for authorization.

mdgilene avatar Aug 28 '23 18:08 mdgilene