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

Mappers.getMapper(Class clazz) is throwing a ClassNotFoundException when a mapper is defined with a custom implementation name. #1812

Closed
matleclaire opened this issue May 10, 2019 · 5 comments

Comments

@matleclaire
Copy link

Hey guys !

I've discovered what it seems to be an issue with Mappers.getMapper(Class<T> clazz) when a Mapper is defined this way

// Pay attention to the implementationName which has been defined
@Mapper(componentModel = "spring", implementationName = "<CLASS_NAME>V1Impl")
public interface CarMapper {
  @Mapping(target = "color", ignore = true)
  CarDTO map(Car car);

}

And when we try to retrieve its implementation using Mappers.getMapper(CarMapper.class).

Here is the stacktrace

Caused by: java.lang.ClassNotFoundException: Cannot find implementation for com.example.demo.mappers.v1.CarMapper
	at org.mapstruct.factory.Mappers.getMapper(Mappers.java:75)
	at org.mapstruct.factory.Mappers.getMapper(Mappers.java:58)

The issue seems to be located here

throw new ClassNotFoundException("Cannot find implementation for " + mapperType.getName() );

The code is trying to load a mapper according to the default class implementation name. The one defined by implementationName in annotation @Mapper is not considered here.

I've created a public repo to reproduce this behaviour.
see https://github.com/matleclaire/mapstruct-sample-error

I hope it might help.

Mapstruct version : 1.3.0-Final

@chris922
Copy link
Member

Thanks @matleclaire for reporting this!

When you use the component model spring it is not expected that you retrieve the mapper with Mappers.getMapper(...). Could you try to remove the component model and do it once again ? Or let Spring inject the mapper.

Mappers.getMapper(...) needs some metadata in case the generated class has a different suffix, this will only be generated in case the component model is not set / the default one. In this case the Java ServiceLoader will be used to retrieve the class when I remember correctly...

@filiphr
Copy link
Member

filiphr commented May 24, 2019

As @chris922 said, the Mappers factory is there to provide a convenience way of getting Mappers with the default component model.

It doesn't support mappers with custom name. And it can't read the @Mapper annotation, since this annotation is not retained in the byte code (it is a source annotation only).

As @chris922 also said if it can't find a class finishing with Impl it will use the Java ServiceLoader.

I am closing this since this is works as designed.

Keep in mind that you can still instantiate the class by calling the Impl constructor.

@filiphr filiphr closed this as completed May 24, 2019
@matleclaire
Copy link
Author

My comment comes very lately, sorryfor that.

Thanks for all your feedbacks and your explanations. That's pretty clear now.

@FlyingDream941228
Copy link

Is your problem solved?
How to solve it

@sjaakd
Copy link
Contributor

sjaakd commented Sep 26, 2020

Is your problem solved?
How to solve it

Please don't respond to closed issues. Ask questions on stackoverflow

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

No branches or pull requests

5 participants