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

Add support for direct type parameters in generators #26

Closed
Nirei opened this issue May 16, 2021 · 1 comment
Closed

Add support for direct type parameters in generators #26

Nirei opened this issue May 16, 2021 · 1 comment
Assignees
Labels
enhancement New feature or request

Comments

@Nirei
Copy link
Collaborator

Nirei commented May 16, 2021

Currently, when a generator needs to produce generics, implementation details of the library need to be exposed to the user, who needs to receive a Class<T> type parameter (plus constraining annotations) to be able to manually call Generators.gen.

Instead of having the user receive Class<T> class and Class<?> annotations in user-defined generate() methods add support for using type parameters directly:

Hiding implementation details

At present time, our generator implementation for generic classes look something like this:

@Generated("com.jtheories.core.generator.processor.GeneratorProcessor")
public final class GenericThingGenerator<T> implements ThingGenerator, Generator<Thing> {
  public GenericThing generateConstrained(Class type, Class... annotations) {
    return GenericThing.super.generate(type, annotations);
  }
}

Internally, they are called with the type parameter of the generated class. They go on to pass that class to the user's default implementation. The user then uses that received type to manually call Generators or another specific generator like this:

	default List<T> generate(Class<T> type, Class<T>... constrains) {
		var elementGenerator = Generators.gen(type, constrains);
               ...
	}

This is a clear schism in the usual API we are usually trying to provide for our users, in which they just ask for the parameters they need to build their target class, such as this:

default Short generate(SourceOfRandom random) {...}

or this:

	default Product generate(UUID id, String name, @Positive @NotMultipleOf10 Long price) {...}

To solve this problem and hide specific parameterizing types from the user, it'd be better if we did the following instead:

In the user-defined generator the user declares parameters as usual. If they don't know the specific type of a parameter, they introduce a variable-type parameter in their generator function:

    default <A, B> MyParameterizedType<A, B> generate(A a, B b, String string, Long aLong) {
        return MyParameterizedType.builder()
            .setA(a)
            .setB(b)
            .setString(string)
            .setLong(aLong)
            .build();
    }

Internally, when a test or otherwise needs to generate a value of MyParameterizedType<SpecificX, SpecificY>, the type parameters will be resolved and the implementation will be called. The implementation receives those type parameters as input, resolves them to specific values, just the same as any other type, and then calls the user code:

@Generated("com.jtheories.core.generator.processor.GeneratorProcessor")
public final class MyParameterizedType<A, B> implements MyParameterizedGenerator, Generator<MyParameterizedType<A, B>> {
  public <A, B> MyParameterizedType<A, B> generateConstrained(
        Class<A> typeA, Class[] annotationsA,
        Class<B> typeB, Class[] annotationsB,
        Class[] annotationsString, Class[] annotationsLong) {
    var random_A = Generators.gen(typeA, annotationsA);
    var random_B = Generators.gen(typeB, annotationsB);
    var random_string = Generators.gen(String.class, annotationsString);
    var random_long = Generators.gen(Long.class, annotationsLong);
    return MyParameterizedType.super.generate(random_A, random_B, random_string, random_long);
  }
}

In this way, generics are handled just like any other type.

@Nirei Nirei added the enhancement New feature or request label May 16, 2021
@hryuk hryuk self-assigned this May 16, 2021
@hryuk
Copy link
Owner

hryuk commented May 18, 2021

Resolved with c5a7d00
There are still issues with current implementation, like only working with 1 parameter, but will be fixed in future iterations.

@hryuk hryuk closed this as completed May 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants