Kotlin

[Kotlin] Java 코드(Function, static, IntStream, mapToObj) -> Kotlin 코드 변환

nineDeveloper 2021. 8. 1.
728x90

기존에 Java 에서 작업한 코드를 Kotlin 으로 변환하면서 기록한다

공통 엑셀 다운로드 기능 코드인데 Java 코드를 Kotlin 으로 변환하는 부분이 약간 햇갈려서 삽질을 조금 했다

1. 엑셀 업로드 Sample 객체 변환

Java 버전

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
@ApiModel("Sample 엑셀 업로드 객체")
public class SampleExcel {
    @NotEmpty//(message = "이름은 필수 입력값 입니다")
    @ApiModelProperty(value = "이름", position = 1)
    private String name;
    @ApiModelProperty(value = "이메일", position = 2)
    private String email;
    @NotEmpty//(message = "전화번호는 필수 입력값입니다")
    @ApiModelProperty(value = "전화번호", position = 3)
    private String phone;
    @NotEmpty//(message = "소속부서는 필수 입력값입니다")
    @ApiModelProperty(value = "소속부서", position = 4)
    @Size(min = 1, max = 10)
    private String dept;
    @NotNull//(message = "업무코드는 필수 입력값입니다")
    @ApiModelProperty(value = "업무코드", position = 5)
    private Integer workCode;
    @NotNull//(message = "부서코드는 필수 입력값입니다")
    @ApiModelProperty(value = "부서코드", position = 6)
    private Integer deptCode;
    @Size(min = 1, max = 500)
    @ApiModelProperty(value = "내용", position = 7)
    private String content;
    @Size(max = 15)
    @Pattern(regexp="(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])", message="IP 주소 형식이 올바르지 않습니다")
    @ApiModelProperty(value = "IP", position = 8)
    private String ip;
    @ApiModelProperty(value = "소수", position = 9)
    private Double percent;
    @ApiModelProperty(value = "날짜", position = 10)
    private String createDate;
    @ApiModelProperty(value = "일시", position = 11)
    private String updateDatetime;
    @ApiModelProperty(value = "빈데이터", position = 12)
    private String emptyData;

    /**
     * 엑셀 업로드 처리를 위한 객체
     * @param row
     * @return
     */
    public static SampleExcel from(Row row) {
        return ExcelUtils.setObjectMapping(new SampleExcel(), row);
    }
}

 

⬇︎⬇︎⬇︎⬇︎

 

Kotlin

참고로 springfox 버전의 Swagger 를 사용했었는데 MSA 지원이나 최근까지 활발히 업데이트가 되고 있는 springdoc 로 변경했다
springfox@ApiModel,@ApiModelProperty 어노테이션 들은 springdoc 에서는 @Schema로 사용된다

Kotlin 에서는 () 안에 기본생성자로 생성한 객체 속성값에 어노테이션 기능을 적용하기 위해 @field를 추가해주어야 정상적으로 적용이 된다

그리고 Kotlin 에서 staticcompanion object 로 선언해서 사용하는 방식으로 사용해야 한다

@Schema(title = "Sample 엑셀 업로드 객체", hidden = true)
class SampleExcel(
    @field:Schema(title = "이름")
    @field:NotEmpty
    var name: String? = null,
    @field:Schema(title = "이메일")
    @field:NotEmpty
    var email: String? = null,
    @field:Schema(title = "전화번호")
    @field:NotEmpty
    var phone: String? = null,
    @field:NotEmpty
    @field:Schema(title = "소속부서")
    var dept: String? = null,
    @field:NotNull
    @field:Schema(title = "업무코드")
    var workCode: Int? = null,
    @field:NotNull
    @field:Schema(title = "부서코드")
    var deptCode: Int? = null,
    @field:Size(min = 1, max = 500)
    @field:Schema(title = "내용")
    var content: String? = null,
    @field:Size(max = 15)
    @field:Pattern(regexp="(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])", message = "IP 주소 형식이 올바르지 않습니다")
    @field:Schema(title = "IP")
    var ip: String? = null,
    @field:Schema(title = "소수")
    var percent: BigDecimal? = null,
    @field:Schema(title = "날짜")
    var createDate: String? = null,
    @field:Schema(title = "일시")
    var updateDatetime: String? = null,
    @field:Schema(title = "빈데이터")
    var empty: String? = null,
) {

    override fun toString(): String {
        return "SampleExcel(name=$name, email=$email, phone=$phone, dept=$dept, workCode=$workCode, deptCode=$deptCode, content=$content, ip=$ip, percent=$percent, createDate=$createDate, updateDatetime=$updateDatetime, empty=$empty)"
    }

    companion object {
        /**
         * 엑셀 업로드 처리를 위한 객체
         * @param row Row
         * @return SampleExcel?
         */
        fun from(row: Row): SampleExcel = ExcelUtils.setObjectMapping(SampleExcel(), row)
    }

}

2. 메서드 레퍼런스(Methond Reference) 를 사용하는 Function 인자값 변환

Java 버전

Java 버전에서는 Function<Row, T> rowfunc 인자값 전달을 위해 SampleExcel::from 메서드 레퍼런스를 전달하면 되었다

List<SampleExcel> sampleExcelList = ExcelReader.getObjectList(file, SampleExcel::from);
public static <T> List<T> getObjectList(final MultipartFile multipartFile, final Function<Row, T> rowFunc) {

 

⬇︎⬇︎⬇︎⬇︎

 

Kotlin 버전

Kotlin 버전에서는 Function<Row, T> rowfunc 인자값 전달을 위해 동일한 코드가 동작하지 않았고
아래와 같이 Lambda 함수로 변환하여 전달하여야 동일하게 동작되었다

val sampleExcelList: List<SampleExcel> = ExcelReader.getObjectList(file) { row -> SampleExcel.from(row) }
fun <T> getObjectList(multipartFile: MultipartFile, rowFunc: Function<Row, T>): List<T> {

3. IntStream, mapToObj 를 Kotlin 코드로 변환

Java 버전

List<T> objectList = IntStream
        .range(startRow, rowCount)
        .filter(rowIndex -> isPass(sheet.getRow(rowIndex)))
        .mapToObj(rowIndex -> rowFunc.apply(sheet.getRow(rowIndex)))
        .collect(Collectors.toList());
/**
 * 해당 ROW에 있는 데이터가 모두 비어있으면 빈 ROW로 판단하고 해당 ROW는 PASS 시킨다
 * @param row
 * @return
 */
private static boolean isPass(Row row) {
    int i =0;
    boolean isPass = false;
    while (i < row.getPhysicalNumberOfCells()) {
        if(StringUtils.isNotEmpty(ExcelUtils.getValue(row.getCell(i++))))
            isPass = true;
    }
    return isPass;
}

 

⬇︎⬇︎⬇︎⬇︎

 

Kotlin 버전

Kotlin 에서는 IntStream.range를 사용할 필요 없이 아래와 같이 Range expression 을 구현할 수 있다
mapToObjKotlin 에서 map 으로 구현하면 된다
또한 Java 에서 .collect(Collectors.toList()) 장황하게 길던 코드를 Kotlin 에서는 .toList() 로 간결하게 표현할 수 있다

val objectList =
    (startRow until rowCount)
        .filter { isPass(sheet.getRow(it)) }
        .map { rowFunc.apply(sheet.getRow(it)) }
        .toList()

위의 로직의 filter 에서 사용되어지는 isPass 메서드도 불필요한 i 변수를 제거하고 Range expression 을 사용하여 아래와 같이 변환하였다

/**
 * 해당 ROW에 있는 데이터가 모두 비어있으면 빈 ROW로 판단하고 해당 ROW는 PASS 시킨다
 * @param row
 * @return
 */
private fun isPass(row: Row): Boolean {
    var isPass = false
    (0 until row.physicalNumberOfCells).forEachIndexed { i, it ->
        if (StringUtils.isNotEmpty(ExcelUtils.getValue(row.getCell(i)))) isPass = true
    }
    return isPass
}
728x90

댓글

💲 추천 글