w201
w201

Reputation: 2228

Mapstruct kotlin and @Named annotation

I'm converting some pet project from java to kotlin and stuck with some problem that can't solve. In java all compile fine but after convertation to Kotlin doesn't want....

...
import org.mapstruct.Mapper
import org.mapstruct.Mapping
import org.mapstruct.Named
...

@Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR)
interface EffectMapper {

    @Mapping(source = "icon", target = "icon", qualifiedByName = ["convertIcon"])
    fun toDS(effectDTO: EffectDTO): EffectDS

    fun toDSarr(effectDTOArrayList: ArrayList<EffectDTO>): ArrayList<EffectDS>

    @Named("convertIcon")
    fun convertIcon(obj: String?): ByteArray? {
        return if (obj != null) {
            Base64.decode(obj, Base64.DEFAULT)
        } else {
            null
        }
    }

    companion object {
        val MAPPER = Mappers.getMapper(EffectMapper::class.java)
    }
}

Gradle return error

 error: Can't generate mapping method from non-iterable type to iterable type.
    public abstract byte[] convertIcon(@org.jetbrains.annotations.Nullable()

and

Can't map property "java.lang.String icon" to "byte[] icon". Consider to declare/implement a mapping method: "byte[] map(java.lang.String value)".
    @org.mapstruct.Mapping(source = "icon", target = "icon", qualifiedByName = {"convertIcon"})

and

Can't map property "java.lang.String effect" to "one.codium.funart.DataStructure.effect.Effect effect". Consider to declare/implement a mapping method: "one.codium.funart.DataStructure.effect.Effect map(java.lang.String value)".
    public abstract one.codium.funart.DataStructure.EffectDS toDS(@org.jetbrains.annotations.NotNull()

finally it was done by this way

@Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR, uses = [EffectMapperImpl::class])
interface EffectMapper {

    fun toDS(effectDTO: EffectDTO): EffectDS

    fun toDSarr(effectDTOArrayList: ArrayList<EffectDTO>): ArrayList<EffectDS>

    companion object {
        val MAPPER: EffectMapper = Mappers.getMapper(EffectMapper::class.java)
    }
}

object EffectMapperImpl {

    fun convertIcon(obj: String?): ByteArray? {
        return if (obj != null) {
            Base64.decode(obj, Base64.DEFAULT)
        } else {
            null
        }
    }

    fun toEffect(s: String): Effect {
        return Effect(s)
    }
}

Thank you @Filip

Upvotes: 5

Views: 6459

Answers (2)

Mr.Q
Mr.Q

Reputation: 4524

I am using Kotlin 1.3.71-release-431 and it works fine with @JvamDefault, so you just need to make your conversion method (toEffect) static in (java).

Mapping(source = "sourceFiledName", target = "destinationFiledName", qualifiedByName = ["converterMethod"])
interface EffectMapper {
  fun toDS(effectDTO: EffectDTO): EffectDS
  
  fun toDSarr(effectDTOArrayList: ArrayList<EffectDTO>): ArrayList<EffectDS>
  
  companion object {
     @JvmStatic
     @Named("converterMethod")
     fun toEffect(s: String): Effect {
        return Effect(s)
      }
  }
}

Upvotes: 6

Filip
Filip

Reputation: 21423

The problem you are seeing is due to the fact that the convertIcon method is not recognized as a default method in the EffectMapper interface.

Even if you use @JvmDefault it won't work due to KT-25960. I would suggest that you extract the convertIcon method into a public static method in another class and then use it via Mapper#uses

Upvotes: 0

Related Questions