These are chat archives for mapstruct/mapstruct-users

25th
Jan 2017
Tyler Thrailkill
@snowe2010
Jan 25 2017 00:12
looks like it was something funky happening in IntelliJ. I wiped .m2 and rebuilt and everything works now. thank you!
Tyler Thrailkill
@snowe2010
Jan 25 2017 00:31
well I thought i had it working, but I only got the example I sent working, my code still doesn't work.
dang
Gerrit Erpenstein
@GerritErpenstein
Jan 25 2017 11:50

Hi everybody! I am currently reviewing MapStruct to be used in our project.
We have A LOT (!) of JPA entities that all implement the Spring interface 'Persistable<UUID>' that defines the method 'UUID getId()'. For nested entities we just need the getId() value in our DTOs (instead of deep object mapping).
My naive approch was to implement a mapper class in the following form:

public class PersistableMapper {
    public UUID map(final Persistable<UUID> persistable) {
        return persistable.getId();
    }
}

Well, this doesn't work as MapStruct doesn't check if the entity's subtype (Persistable) matches:

Can't map property "foo.MyNestedEntity nestedEntity" to "java.util.UUID myEntityId". Consider to declare/implement a mapping method: "java.util.UUID map(foo.MyNestedEntity  value)"

I have digged through the docs and the JUnit Tests a few hours but couldn't find (or missed) our particular use case.
Can anyone point me to the right direction?

Andreas Gudian
@agudian
Jan 25 2017 11:55
That's exactly how you'd do it. Did you add your PersistableMapper in @Mapper(uses = { PersistableMapper.class } of the actual mapper?
Gerrit Erpenstein
@GerritErpenstein
Jan 25 2017 12:23
Yes, that's exactly what I added.
@Mapper(componentModel = "spring", uses = { PersistableMapper.class })
public interface MyEntityMapper {
    //...
I will try to move the code out of our complex project and create a minimal example. Maybe something is interfering. Weird...
Gerrit Erpenstein
@GerritErpenstein
Jan 25 2017 13:46
I have created a minimal test case: https://github.com/GerritErpenstein/mapstruct-subtype-test
The problem persists. Did I stumble over a bug?
Andreas Gudian
@agudian
Jan 25 2017 14:04
I'll have a look at it tonight... 🙂
Gerrit Erpenstein
@GerritErpenstein
Jan 25 2017 14:08
Great! Thank you very much. :)
Tyler Thrailkill
@snowe2010
Jan 25 2017 19:18
this is so weird. I keep getting that can't map property error on my mac, but not on my windows box.
:/
Filip Hrisafov
@filiphr
Jan 25 2017 19:18
That is really weird. Are you using the same Java on both of the machines?
Tyler Thrailkill
@snowe2010
Jan 25 2017 19:31
it's 1.8.0_73 v 1.8.0_121. the newer version is on the windows box because I just reinstalled windows last week
I'll probably complete my work on my windows box and then wipe my m2 repo and intellij and stuff and retry on the mac when I'm done. that way I know it works, but can stop battling other issues at the same time.
Filip Hrisafov
@filiphr
Jan 25 2017 19:33
maybe just try and update the Java on the mac
maybe that is the issue
Tyler Thrailkill
@snowe2010
Jan 25 2017 19:34
will do.
Andreas Gudian
@agudian
Jan 25 2017 19:40
@GerritErpenstein, you indeed found a bug here, and it seems like it has been there in 1.0.0.Final already. I'll take a closer look to see what's wrong. In the meantime, this works as well:
@Mapper
public interface SourceMapper {
    @Mapping(source = "nested.id", target = "nestedId")
    Target toTarget(Source source);
}
Tyler Thrailkill
@snowe2010
Jan 25 2017 20:47
how does mapstruct find properties? e.g. if my class has a property with lowercase letters but the getter has all uppercase, which should I use in the target directive?
    protected DATAINFORMATION datainformation;
    public void setDATAINFORMATION(DATAINFORMATION value) {
        this.datainformation = value;
    }
Andreas Gudian
@agudian
Jan 25 2017 20:56
We use java.beans.Introspector.decapitalize(String) to convert the method name (without the get/set prefix) to the property name - that method should conform to the Java Bean Specification
So as per Bean Specification, your bean property is called DATAINFORMATION.
Tyler Thrailkill
@snowe2010
Jan 25 2017 20:58
so I don't need to specify it as loanApplication.PROPERTY.structureBuiltYear, I can just do loanApplication.property.structureBuiltYear.
Andreas Gudian
@agudian
Jan 25 2017 21:00
no, the property name would be PROPERTY if it's getPROPERTY / setPROPERTY.
   /**
     * Utility method to take a string and convert it to normal Java variable
     * name capitalization.  This normally means converting the first
     * character from upper case to lower case, but in the (unusual) special
     * case when there is more than one character and both the first and
     * second characters are upper case, we leave it alone.
     * <p>
     * Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays
     * as "URL".
     *
     * @param  name The string to be decapitalized.
     * @return  The decapitalized version of the string.
     */
    public static String decapitalize(String name) {
         ...
    }
Tyler Thrailkill
@snowe2010
Jan 25 2017 21:01
ah.. that's a confusing method name.
kinda
Tyler Thrailkill
@snowe2010
Jan 25 2017 21:09
man I do not understand why I'm getting these errors then
[ERROR] /C:/Users/Tyler/Documents/dev/work/lp-server/lp-server-read/src/main/java/com/company/something/PropertyMapper.java:[22,13] Unknown property "loanApplication.PROPERTY.financedNumberOfUnits" in return type.
It was working, and then I started working on a second part of the codebase and it just started failing again.
Andreas Gudian
@agudian
Jan 25 2017 21:14
are parts of your classes being generated by another annotation processor?
Tyler Thrailkill
@snowe2010
Jan 25 2017 21:14
the classes in question are generated by the jaxb2-maven-plugin in another project that is a dependency in this project.
Andreas Gudian
@agudian
Jan 25 2017 21:15
you get the build errors when building with Maven, I suppose?
Tyler Thrailkill
@snowe2010
Jan 25 2017 21:15
I guess one of the classes is a kotlin class, but it's not generated by an annotation processor. It's an on the fly thing by either a maven plugin or intellij
yes
but also when just trying to run a test with intellij
Andreas Gudian
@agudian
Jan 25 2017 21:16
ahh... that could be what's causing this, if IntelliJ perhaps regenerates some classes asynchronously?
Tyler Thrailkill
@snowe2010
Jan 25 2017 21:17
but it wouldn't happen if I just ran from the command line right?
Andreas Gudian
@agudian
Jan 25 2017 21:17
right, unless IntelliJ is running / refreshing in the background... do you have auto-building on?
Tyler Thrailkill
@snowe2010
Jan 25 2017 21:18
ah. I see. Hmm. let me check
Andreas Gudian
@agudian
Jan 25 2017 21:18
just a hunch, though...
Tyler Thrailkill
@snowe2010
Jan 25 2017 21:18
no it's not on :(
Filip Hrisafov
@filiphr
Jan 25 2017 21:20
and the kotlin maven plugin runs before the maven compiler right?
Tyler Thrailkill
@snowe2010
Jan 25 2017 21:20
hmm. I don't know how to check that. I didn't set up our parent pom.
is that just the order in the parent?
Andreas Gudian
@agudian
Jan 25 2017 21:20
if the build result is not reproducible, you could try to move the other generated parts to different maven modules, mvn clean install them and then only mvn clean install the module that contains the mappers. If that works, then there could be some problem with the kotlin plugin. If the error still pops up, you could check what's actually inside the jars of the other projects.
Tyler Thrailkill
@snowe2010
Jan 25 2017 21:21
what do you mean check what's actually inside the jars of the other projects?
I've ctrl clicked into them and everything looks good in the class files.
Andreas Gudian
@agudian
Jan 25 2017 21:22
and the build of the single module with only the mappers inside still fails?
Tyler Thrailkill
@snowe2010
Jan 25 2017 21:23
Haven't tried moving mappers just to their own module. let me try real quick
Tyler Thrailkill
@snowe2010
Jan 25 2017 21:48
still failed even in another module.
is the problem that I need a mapper for the nested properties?
@Mapper(componentModel = "spring")
public interface PropertyMapper {
    public static final PropertyMapper INSTANCE = Mappers.getMapper(PropertyMapper.class);

    @Mappings({
            @Mapping(source = "property.propertyDetails.yearBuilt", target = "loanApplication.property.structureBuiltYear"),
            @Mapping(source = "property.propertyDetails.numberOfUnits", target = "loanApplication.PROPERTY.financedNumberOfUnits"),
    })
    void updateFromProperty(PropertyRegisteredEvent event, @MappingTarget AFile file);

}
AFile looks like
data class AFile(
        val loanId: LoanId,
        val loanTransactionId: LoanTransactionId,
        override var tenantId: TenantId,
        val loanApplication: LOANAPPLICATION
) : AbstractView {
Filip Hrisafov
@filiphr
Jan 25 2017 21:51
your first mapping has lowercase property and your second one has uppercase PROPERTY
Tyler Thrailkill
@snowe2010
Jan 25 2017 21:51
yeah they're both failing
[ERROR] /C:/Users/Tyler/Documents/dev/work/lp-server/lp-server-mappers/src/main/java/com/company/loanapp/mappers/PropertyMapper.java:[23,13] Unknown property "loanApplication.PROPERTY.financedNumberOfUnits" in return type.
[ERROR] /C:/Users/Tyler/Documents/dev/work/lp-server/lp-server-mappers/src/main/java/com/company/loanapp/mappers/PropertyMapper.java:[22,13] Unknown property "loanApplication.property.structureBuiltYear" in return type.
Filip Hrisafov
@filiphr
Jan 25 2017 21:55
how does the getter of AFile look like?
maybe kotlin is not generating it well
Tyler Thrailkill
@snowe2010
Jan 25 2017 21:56
getLoanApplication()
public class LOANAPPLICATION {
    protected LOANQUALIFICATION loanqualification;
    protected PROPERTY property;
    protected TRANSACTIONDETAIL transactiondetail;
    ...
    public PROPERTY getPROPERTY() {
        return property;
    }
    public void setPROPERTY(PROPERTY value) {
        this.property = value;
    }
    ...
public class PROPERTY {
...
    protected String county;
    protected String postalCode;
    protected String buildingStatusType;
    protected String financedNumberOfUnits;
    protected String structureBuiltYear;
    protected String acquiredDate;
    protected String plannedUnitDevelopmentIndicator;
    protected String acreageNumber;
    ...
    public String getStructureBuiltYear() {
        return structureBuiltYear;
    }
    public void setStructureBuiltYear(String value) {
        this.structureBuiltYear = value;
    }
    ...
those classes are generated in a different jar, so I don't think they're the problem.
Filip Hrisafov
@filiphr
Jan 25 2017 21:59
can you try to make AFile a java class and see if it works
Tyler Thrailkill
@snowe2010
Jan 25 2017 21:59
problem is I tried to reproduce in a smaller project and everything seemed to work. That was on a mac. Then I switched to windows, it started working fine and then suddenly broke! I didn't change anything between the two.
yes
Filip Hrisafov
@filiphr
Jan 25 2017 22:00
and you didn't change the kotlin version?
Tyler Thrailkill
@snowe2010
Jan 25 2017 22:00
no, I just pushed my changes to git, repulled on the windows box and reran and it worked.
Tyler Thrailkill
@snowe2010
Jan 25 2017 22:16
back to the can't map property error.
:compile (default-compile) on project lp-server-mappers: Compilation failure
[ERROR] /C:/Users/Tyler/Documents/dev/work/lp-server/lp-server-mappers/src/main/java/com/company/mappers/PropertyMapper.java:[27,10] Can't map property "java.lang.Integer propertyRegisteredEvent.property.propertyDetails.numberOfUnits" to "java.lang.String financedNumberOfUnits". Consider to declare/implement a mapping method: "java.lang.String map(java.lang.Integer value)".
[ERROR] -> [Help 1]
[ERROR]
that's with making AFile into a java file.