Skip to content

Allow factories to return a dynamically created class #3472

@xenoterracide

Description

@xenoterracide

Use case

So I've seen the documentation on using factories. I'm trying to use Byte Buddy to create a subclass.

var clazz =
  new ByteBuddy()
    .subclass(entityClass)
    .defineField(
            MODIFICATIONS_FIELD, GroupModifications.class, Opcodes.ACC_PUBLIC)
    .method(ElementMatchers.isSetter())
    .intercept(MethodDelegation.to(GroupChangeTrackingProxy.class))
    .make()
    .load(GroupProxyFactory.class.getClassLoader())
    .getLoaded();

What I'd like to be able to do is return this class for a constructor that should otherwise match the constructors given on the real class.

Part of the problem here is that some of the fields on this class are final and need to be created with the constructor.

There are 2 constructors, one with 3 args, and one no arg. Unfortunately this is openapi generated code so I also don't really control that class either... Although I could strip that no arg constructor out of the subclass ;) .

Generated Code

I'm doing something like this... I'm using spring utils and vavr to avoid checked exceptions, you probably don't want to generate with those instead using the raw reflection api. currently this isn't going to work as written. I'd want the generated code to rethrow a checked exception as a runtime exception.

    private static <T> T createInstanceOf(Class<? extends T> clazz) {
        var ctors = Stream.of(clazz.getDeclaredConstructors());
        var found =
                ctors.filter(ctor -> ctor.getParameterCount() > 0)
                        .findFirst()
                        .map(
                                ctor ->
                                        Try.of(() -> ctor.newInstance())
                                                .getOrElseThrow(ex -> new RuntimeException(ex)));

        @SuppressWarnings("unchecked")
        var res = (T) found.orElseThrow();
        return res;
    }

Possible workarounds

I'm trying to think about how I could get those constructor parameters. Most likely I can't use mapstruct to instantiate this. I'll have to write something more custom for each class that needs this.

MapStruct Version

1.5.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions