Issue
I have a bunch of same-named classes with same attrubutes in various packages. Let's say each class looks like this:
public class MiddlewareHeaderType {
private String longPrefixRequestId;
private String abcReason;
private String defSubject;
}
com.mycompany.generated.ws.serviceA.MiddlewareHeader;
com.mycompany.generated.ws.serviceB.MiddlewareHeader;
com.mycompany.generated.ws.serviceC.MiddlewareHeader;
...
I am unable to change these as long as they are generated (let's say from a XSD). I want to have a generic object, say MySoapHeader
to be used as a source data convertible into such generated classes using MapStruct and Java 11 (I am not limited to just Java 8 features).
public class MySoapHeader {
private String requestId;
private String reason;
private String subject;
}
I am reluctant to create a separate mapper class for each of the generated header object as long as there are, let's say, hundreds of them. But they are pretty much the same.
My attempt doesn't work with a generic value and I havent found anywhere an answer dealing with the similar problem:
@Named("base")
@Mapping(target = "longPrefixRequestId", source = "requestId")
@Mapping(target = "abcReason", source = "reason")
@Mapping(target = "defSubject", source = "subject")
<T> T base(MySoapHeader mySoapHeader);
@Mapping(target = "MiddlewareHeaderType", qualifiedByName = "base")
com.mycompany.generated.ws.serviceA.MiddlewareHeaderType serviceAHeader(MySoapHeader mySoapHeader);
@Mapping(target = "MiddlewareHeaderType", qualifiedByName = "base")
com.mycompany.generated.ws.serviceB.MiddlewareHeaderType serviceBHeader(MySoapHeader mySoapHeader);
@Mapping(target = "MiddlewareHeaderType", qualifiedByName = "base")
com.mycompany.generated.ws.serviceC.MiddlewareHeaderType serviceCHeader(MySoapHeader mySoapHeader);
Solution
What you are looking for is something like mapping composition. We have added this support in 1.4 (still in Beta now).
With this you can define your own custom mapping annotation.
e.g.
@Retention(RetentionPolicy.CLASS)
@Mapping(target = "longPrefixRequestId", source = "requestId")
@Mapping(target = "abcReason", source = "reason")
@Mapping(target = "defSubject", source = "subject")
public @interface SoapHeaderMapping { }
And then in your mapper you can do:
@Mapper
public interface HeaderMapper {
@SoapHeaderMapping
com.mycompany.generated.ws.serviceA.MiddlewareHeaderType serviceAHeader(MySoapHeader mySoapHeader);
@SoapHeaderMapping
com.mycompany.generated.ws.serviceB.MiddlewareHeaderType serviceBHeader(MySoapHeader mySoapHeader);
@SoapHeaderMapping
com.mycompany.generated.ws.serviceC.MiddlewareHeaderType serviceCHeader(MySoapHeader mySoapHeader);
}
More info can be found here
Answered By - Filip
Answer Checked By - Cary Denson (JavaFixing Admin)