mcarleio / konvert

This kotlin compiler plugin is using KSP API and generates kotlin code to map one class to another
https://mcarleio.github.io/konvert/
Apache License 2.0
86 stars 8 forks source link

Is there a good way to convert from Java class to Kotlin data class #54

Closed sato9818 closed 5 months ago

sato9818 commented 6 months ago

Suppose I have a following java class.

public final class Request {
    private String field_ = "";

    public String getField() {
        return field_;
    }
}

I got an error with a following kotlin data class.

@KonvertFrom(Request::class)
data class RequestDto(
    private val field: String
) {
    companion object
}

Error:

[ksp] io.mcarle.konvert.processor.exceptions.PropertyMappingNotExistingException: No property for valueParameter=field existing in [PropertyMappingInfo(mappingParamName=request, sourceName=field_, targetName=field_, constant=null, expression=null, ignore=false, enableConverters=[], declaration=field_, isBasedOnAnnotation=false)]

I could generate a converter code but also got an error with a following kotlin data class.

@KonvertFrom(
    Request::class,
    mappings = [
        Mapping(
            target = "field",
            source = "field_"
        )
    ],
    options = [
        Konfig(key = "konvert.enforce-not-null", value = "true")
    ]
)
data class RequestDto(
    private val field: String
) {
    companion object
}

Generated code:

@GeneratedKonverter(priority = 4_000)
public fun RequestDto.Companion.fromRequest(request: Request): RequestDto = RequestDto(
  field = request.field_!!
)

Error:

Cannot access 'field_': it is private in 'Request'

Finally, I could generate a converter code without any error by using expression option.

@KonvertFrom(
    Request::class,
    mappings = [
        Mapping(
            target = "field",
            expression = "it.getField()"
        )
    ],
    options = [
        Konfig(key = "konvert.enforce-not-null", value = "true")
    ]
)
data class RequestDto(
    private val field: String
) {
    companion object
}

Generated code:

@GeneratedKonverter(priority = 4_000)
public fun RequestDto.Companion.fromRequest(request: Request): RequestDto = RequestDto(
  field = request.let { it.getField() }
)

Is there a other good way to convert than using expression option?

For String field, using the expression option is fine. However, if the field type is Enum and, Request and RequestDto have different Enum type field, how can I convert the class by using konvert? I believe expression option and a custom converter are not applied at the same time.

In my situaltion, Java class is generated code from protocol buffer so I can't edit it.

mcarleio commented 5 months ago

Thanks for bringing this up. The code to collect the source properties anyway had some flaws. I rewrote that now and added getter for better Java compatibility. Your original code should work now. Only thing you probably have to do is activate konvert.enforce-not-null (probably makes sense to enable it globally when dealing with Java classes, see https://mcarleio.github.io/konvert/options/#how-to-set-options)

sato9818 commented 5 months ago

@mcarleio My code works fine with the latest version. Thank you for your quick support!