Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow registration of a Supplier of Randomizers #28 #96

Closed

Conversation

PascalSchumacher
Copy link
Collaborator

Just a quick prototype and not exactly what was requested in #28, but maybe good enough?

@coveralls
Copy link

Coverage Status

Coverage increased (+0.1%) to 75.094% when pulling 8efd2ed on PascalSchumacher:randomizer_supplier into df17980 on benas:master.

@PascalSchumacher
Copy link
Collaborator Author

updated

@coveralls
Copy link

Coverage Status

Coverage increased (+0.1%) to 75.423% when pulling 32dda3d on PascalSchumacher:randomizer_supplier into 7f68fb9 on benas:master.

@fmbenhassine
Copy link
Member

Hello Pascal,

Thanks for implementing this feature. I think the idea of #28 is to use Suppliers as Randomizers, ie, Suppliers will supply random values directly and not supply randomizers.

Looking at this change:

public <T, F, R> EnhancedRandomBuilder randomize(FieldDefinition<T, F> fieldDefinition, Supplier<Randomizer<R>> randomizerSupplier)

Instead, I guess this would be

public <T, F, R> EnhancedRandomBuilder randomize(FieldDefinition<T, F> fieldDefinition, Supplier<R> randomizerSupplier)

This is quite similar to the API suggested in #28. Do you see the difference?

Just a quick prototype and not exactly what was requested in #28, but maybe good enough?

I saw you changes and I believe this is good enough. But I've got another idea on how to implement this and I would like to know what do you think about it.

Instead of having two mappings (one for randomizers and one for suppliers):

private Map<FieldDefinition<?, ?>, Randomizer<?>> customRandomizersRegistry = new HashMap<>();
private Map<FieldDefinition<?, ?>, Supplier<?>> customRandomizersSupplierRegistry = new HashMap<>();

and the corresponding logic to both of them, my idea is to dynamically create a proxy randomizer for the supplier provided by the user. This way, everything remains intact, we only need to adapt the Supplier into a Randomizer. Here is a quick prototype:

import io.github.benas.randombeans.api.Randomizer;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.function.Supplier;

class RandomizerProxy implements InvocationHandler {

    private Object target;

    public RandomizerProxy(final Object target) {
        this.target = target;
    }

    public static Randomizer asRandomizer(final Supplier supplier) {
        return (Randomizer) Proxy.newProxyInstance(
                Randomizer.class.getClassLoader(),
                new Class[]{Randomizer.class},
                new RandomizerProxy(supplier));
    }

    @Override
    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
        if ("getRandomValue".equals(method.getName())) {
            return target.getClass().getMethod("get").invoke(target, args);
        }
        return null;
    }
}

and a test:

import io.github.benas.randombeans.api.Randomizer;
import org.junit.Test;

import java.util.function.Supplier;

import static org.assertj.core.api.Assertions.assertThat;

public class RandomizerProxyTest {

    @Test
    public void testAsRandomizer() throws Exception {
        MySupplier supplier = new MySupplier();
        Randomizer randomizer = RandomizerProxy.asRandomizer(supplier);
        Object randomValue = randomizer.getRandomValue();

        assertThat(randomValue).isInstanceOf(String.class).isEqualTo("foo");
    }

    class MySupplier implements Supplier<String> {

        @Override
        public String get() {
            return "foo";
        }
    }
}

At registration time, we need to call the RandomizerProxy.asRandomizer(supplier) method with the supplier provided by the user. Do you see the idea?

This way, we can register Suppliers and Randomizers in a consistent way. Random Beans will create a dynamic proxy for the Supplier at runtime. This technique will allow us to add support for guava supplier or any other type easily without impacting the internal logic.

I would love to hear your thoughts.
Kind regards
Mahmoud

@PascalSchumacher
Copy link
Collaborator Author

Hi Mahmoud,

like your idea a lot. 😄

It's exactly what was requested in the issue and simple to use.

I was struggling to come up with a way to use a supplier as a randomizer, but you solved it elegantly. 😄

Kind regards,
Pascal

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants