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

SubclassExhaustiveStrategy.RUNTIME_EXCEPTION option does not work if the superclass has a non-empty constructor #2891

Closed
1 task done
prtnv opened this issue Jun 15, 2022 · 1 comment · Fixed by #2893
Closed
1 task done
Labels
Milestone

Comments

@prtnv
Copy link
Contributor

prtnv commented Jun 15, 2022

  • Is this an issue (and hence not a question)?

If the superclass has a non-empty constructor, then MapStruct ignores the subclassExhaustiveStrategy = SubclassExhaustiveStrategy.RUNTIME_EXCEPTION option when generating code

MapStruct 1.5.1.Final, JDK 17

Reproduction scenario:

  @BeanMapping( subclassExhaustiveStrategy = SubclassExhaustiveStrategy.RUNTIME_EXCEPTION )
  @SubclassMapping( source = Source1.class, target = Target1.class )
  @SubclassMapping( source = Source2.class, target = Target2.class )
  AbstractTarget map( AbstractSource source );

  abstract class AbstractTarget {
    private final String name;

    protected AbstractTarget(String name) {
      this.name = name;
    }
    // getter
  }

  class Target1 extends AbstractTarget {
    protected Target1(String name) {
      super(name);
    }
  }

  class Target2 extends AbstractTarget {
    protected Target2(String name) {
      super(name);
    }
  }

  abstract class AbstractSource {
    private final String name;

    protected AbstractSource(String name) {
      this.name = name;
    }
    // getter
  }

  class Source1 extends AbstractSource {
    protected Source1(String name) {
      super(name);
    }
  }

  class Source2 extends AbstractSource {
    protected Source2(String name) {
      super(name);
    }
  }

For this example MapStruct generates the following code

@Override
public AbstractTarget map(AbstractSource source) {
    if ( source == null ) {
        return null;
    }
    if (source instanceof Source1) {
        return source1ToTarget1( (Source1) source );
    }
    else if (source instanceof Source2) {
        return source2ToTarget2( (Source2) source );
    }
    else {
        String name = null;
        name = source.getName();
        AbstractTarget abstractTarget = new AbstractTarget( name );
        return abstractTarget;
    }
}

I was expecting a new IllegalArgumentException to be thrown in the last else statement. And also this generated code doesn't compile due to new AbstractTarget( name )

After some debugging, I think that if change the isAbstractReturnType method in the BeanMappingMethod#isAbstractReturnType class from

public boolean isAbstractReturnType() {
    return getFactoryMethod() == null && !hasConstructorMappings() && returnTypeToConstruct != null
        && returnTypeToConstruct.isAbstract();
}

to

public boolean isAbstractReturnType() {
    return getFactoryMethod() == null ^ hasConstructorMappings() && returnTypeToConstruct != null
        && returnTypeToConstruct.isAbstract();
}

then everything will be fine

Can I try to create PR to fix it?

@prtnv prtnv changed the title The subclassExhaustiveStrategy = SubclassExhaustiveStrategy.RUNTIME_EXCEPTION option does not work if the superclass has a non-empty constructor SubclassExhaustiveStrategy.RUNTIME_EXCEPTION option does not work if the superclass has a non-empty constructor Jun 16, 2022
@antonvovk
Copy link

Hi!
@prtnv I can confirm that I am experiencing exactly the same problem. Thanks for creating an issue.

prtnv added a commit to prtnv/mapstruct that referenced this issue Jun 18, 2022
@filiphr filiphr added this to the 1.5.2 milestone Jun 18, 2022
@filiphr filiphr added the bug label Jun 18, 2022
filiphr added a commit that referenced this issue Jun 18, 2022

Co-authored-by: Filip Hrisafov <filip.hrisafov@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants