Search code examples
javadynamic

Make dynamic method arguments during the compilation in Java


There is the big builder that is the heart of my project and that is used very frequently. I want to make every argument in every method dynamic (expect lambda expression as an agrument). Hovewer, I will need to create twice more methods (or even bigger amount), but my builder class is already too big and I don't want to waste my time, when I add another method to it.

I want to make something like lombok annotation to method to make methods able to receive Supplier<T> and T type argument at the same time. It should get value from the supplier, when it call some method, or get field from the object.

It should be something like

@DynamicArguments
public void randFunc(String string, Integer value) {
   // some code
}
randFunc("word", 1) // works
randFunc(() -> "123546", 3) // works
randFunc(() -> "123456", () -> 8) // works

I've tryed to research groovy and custom lombok annotations to do it, but it didn't help much.


Solution

  • I would use an arguments builder class.

    public static class RandFuncArgs {
        private Supplier<String> string;
    
        private IntSupplier value;
    
        public RandFuncArgs() {
            string("");
            value(0);
        }
    
        public RandFuncArgs(String s,
                            int value) {
            string(s);
            value(value);
        }
    
        public String getString() {
            return s.get();
        }
    
        public int getValue() {
            return value.getAsInt();
        }
    
        public RandFuncArgs string(String s) {
            return string(() -> s);
        }
    
        public RandFuncArgs string(Supplier<String> s) {
            this.string = Objects.requireNonNull(s, "Argument cannot be null.");
            return this;
        }
    
        public RandFuncArgs value(int value) {
            return value(() -> value);
        }
    
        public RandFuncArgs value(IntSupplier value) {
            this.value = Objects.requireNonNull(value, "Argument cannot be null.");
            return this;
        }
    }
    

    Now your outer class just needs one method:

    public void randFunc(RandFuncArgs args) {
        // ...
    }
    

    And others can call it as:

    obj.randFunc(new RandFuncArgs().string("word").value(1));
    obj.randFunc(new RandFuncArgs().string(() -> "123546").value(3));
    obj.randFunc(new RandFuncArgs().string(() -> "123456").value(() -> 8));