```json lines {“command”:”destroy”,”cpu”:99,”status”:”memory overflow”} {“command”:”explode”,”cpu”:100,”status”:”cpu meltdown”} {“command”:”collapse”,”cpu”:95,”status”:”disk burnout”}
- 위 파일은 [json lines](https://jsonlines.org/) 형식의 파일이다.
- json 배열을 작성할 때 `[ ]` 안에 구성하는 것이 아닌 각 줄마다 하나의 json 객체로 저장되어 있다.
- 로그 파일, 스트리밍 데이터 처리 등에서 이런 형식이 사용된다.
- 한 줄씩 구성되어 있기에 아래처럼 `ItemReader`를 구성할 수 있다.
- `lineMapper`에서 `objectMapper`를 사용해 역직렬화
```kotlin
@Bean
@StepScope
fun systemDeathReader(
@Value("#{jobParameters['inputFile']}") inputFile: String,
): FlatFileItemReader<SystemDeath> {
return FlatFileItemReaderBuilder<SystemDeath>()
.name("systemDeathReader")
.resource(ClassPathResource(inputFile))
.lineMapper { line: String, _: Int ->
objectMapper.readValue(line, SystemDeath::class.java)
}
.build()
}
lineMapper
를 그대로 사용하면 에러가 발생한다.```json lines { “command”: “destroy”, “cpu”: 99, “status”: “memory overflow” } { “command”: “explode”, “cpu”: 100, “status”: “cpu meltdown” }
- 어디까지가 하나의 레코드인지 판별하기 위해 `recordSeparatorPolicy`를 사용한다.
- `JsonRecordSeparatorPolicy`는 여는 중괄호(`{`)와 닫는 중괄호(`}`)를 기준으로 하나의 객체를 인식한다.
```kotlin
// ...
.lineMapper { line: String, _: Int ->
objectMapper.readValue(line, SystemDeath::class.java)
}
.recordSeparatorPolicy(JsonRecordSeparatorPolicy())
.build()
}
[
{"command": "destroy", "cpu": 99, "status": "memory overflow"},
{"command": "explode", "cpu": 100, "status": "cpu meltdown"},
{"command": "collapse", "cpu": 95, "status": "disk burnout"}
]
JsonItemReader
를 쓰면 유용하다.@Bean
@StepScope
fun systemDeathReader(
@Value("#{jobParameters['inputFile']}") inputFile: String,
): JsonItemReader<SystemDeath> {
return JsonItemReaderBuilder<SystemDeath>()
.name("systemDeathReader")
.jsonObjectReader(JacksonJsonObjectReader(objectMapper,SystemDeath::class.java))
.resource(ClassPathResource(inputFile))
.build()
}
JsonObjectReader
JacksonJsonObjectReader
GsonJsonObjectReader
JacksonJsonObjectReader
JsonObjectReader
의 잭슨 구현체ObjectMapper
를 함께 생성자에 전달할 수 있다.new
로 기본 매퍼가 생성된다.코틀린의
data class
를 사용하기 위해선ObjectMapper
에 특별한 설정이 필요한데 코프링을 쓰는 경우 빈 주입 받는ObjectMapper
에 그러한 처리가 이미 되어 있다. 위 코드처럼 빈 주입 받은 매퍼를 설정해주면data class
역직렬화를 할 수 있게 된다. 그렇지 않으면 기본 생성자와setter
가 필요하게 되어버린다.
WritableResource
: JSON 데이터를 저장할 대상 파일JsonObjectMarshaller
: 객체럴 JSON 형식으로 마샬링하는 객체 변환기로 다음 두 구현체를 제공한다.
JacksonJsonObjectMarshaller
GsonJsonObjectMarshaller
@Bean
@StepScope
fun systemDeathJsonWriter(
@Value("#{jobParameters['outputDir']}") outputDir: String,
): JsonFileItemWriter<SystemDeath> =
JsonFileItemWriterBuilder<SystemDeath>()
.name("logEntryJsonWriter")
.jsonObjectMarshaller(JacksonJsonObjectMarshaller())
.resource(FileSystemResource("$outputDir/death_notes.json"))
.build()