4

I am trying to generate a class and methods in it, using Byte Buddy, based on some configuration that is available at runtime. The class is trying to create a Hazelcast Jet pipeline to join multiple IMaps.

Based on the provided configuration, the no. of IMaps to join can vary. In the sample below, I am trying to join three IMaps.

private Pipeline getPipeline(IMap<String, Object1> object1Map, IMap<String, Object2> object2Map, 
        IMap<String, Object3> object3Map) {
    Pipeline p = Pipeline.create();

    BatchStage<Entry<String, Object1>> obj1 = p.drawFrom(Sources.map(object1Map));
    BatchStage<Entry<String, Object2>> obj2 = p.drawFrom(Sources.map(object2Map));
    BatchStage<Entry<String, Object3>> obj3 = p.drawFrom(Sources.map(object3Map));

    DistributedFunction<Tuple2<Object1, Object2>, String> obj1Obj2JoinFunc = entry -> entry.f1().getField31();
    DistributedBiFunction<Tuple2<Object1, Object2>, Object3, Tuple2<Tuple2<Object1, Object2>, Object3>> output = (
        in1, in2) -> (Tuple2.tuple2(in1, in2));

    BatchStage<Tuple2<Object1, Object2>> obj1_obj2 = obj1.map(entry -> entry.getValue())
            .hashJoin(obj2.map(entry -> entry.getValue()),
                    JoinClause.onKeys(Object1::getField11, Object2::getField21), Tuple2::tuple2).filter(entry -> entry.getValue() != null);

    BatchStage<Tuple2<Tuple2<Object1, Object2>, Object3>> obj1_obj2_obj3 = obj1_obj2.hashJoin(
            obj3.map(entry -> entry.getValue()),
            JoinClause.onKeys(obj1Obj2JoinFunc, Object3::getField31), output)
            .filter(entry -> entry.getValue() != null);

    // the transformResult method will get the required fields from above operation and create object of AllObjectJoinClass
    BatchStage<Entry<String, AllObjectJoinClass>> result = transformResult(obj1_obj2_obj3);
    result.drainTo(Sinks.map("obj1_obj2_obj3"));
    return p;

}

The problem here is that the no. of arguments to my method depend on the runtime configuration and that determines the method body as well. I am able to generate the method signature using TypeDescription.Generic.Builder.parameterizedType. But, I am having trouble generating the method body. I tried using MethodDelegation.to so that the method resides in a separate class. The trouble with this approach is that the method in the separate class needs to be very generic so that it can take arbitrary no. of arguments of different types and also needs to know about the fields of each of the objects in the IMap.

I wonder if there's an an alternate approach to achieving this with maybe templates of some type so that a separate class can be generated for each pipeline with this body. I didn't find any documentation for generating a method with a defined body (maybe I missed something).

-- Anoop

Anoop
  • 813
  • 2
  • 10
  • 24

1 Answers1

0

It very much depends on what you are trying to do:

  1. With Advice, you can write a template as byte code that is inlined into your method.
  2. With StackManipulations you can compose individual byte code instructions.

It seems to me that option (2) is what you are aiming for. For individually composed code, this is often the easiest option.

Writing individual byte code is of course not the most convenient option but if you can easily compose handling of each input, you might be able to compose multiple Advice classes to avoid using byte code instructions directly.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192