Dennis Tel
03/31/2021, 5:01 PM.windowed
but not sure if this is the way to go. Pretty new to Kotlin and the JVM 😬nanodeath
03/31/2021, 5:06 PMnanodeath
03/31/2021, 5:07 PMDennis Tel
03/31/2021, 5:07 PMoverride fun iterator() = object : Iterator<RawProduct> {
override fun hasNext() = reader.hasNext()
override fun next(): RawProduct {
var item: RawProduct? = null
while (item == null) {
if (reader.next() == XMLStreamReader.START_ELEMENT && reader.name.toString() == "item")
item = xmlMapper.streamValue<Map<String, Any>>(reader).filter { it.value is String } as RawProduct
}
return item
}
But I can’t really figure out how to close the stream if ended prematurelynanodeath
03/31/2021, 5:11 PMsequence {}
with yield
calls insidenanodeath
03/31/2021, 5:11 PMTomasz Krakowiak
03/31/2021, 5:14 PMnanodeath
03/31/2021, 5:15 PMDennis Tel
03/31/2021, 5:15 PMTomasz Krakowiak
03/31/2021, 5:17 PMDennis Tel
03/31/2021, 5:18 PMprivate inline fun <reified T> XmlMapper.streamValue(reader: XMLStreamReader): T =
this.readValue(reader, jacksonTypeRef<T>())
private val xmlMapper = XmlMapper(
JacksonXmlModule().apply {
setDefaultUseWrapper(false)
}).registerKotlinModule()
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) as XmlMapper
nanodeath
03/31/2021, 5:22 PMDennis Tel
03/31/2021, 5:22 PMnanodeath
03/31/2021, 5:23 PMmyInputStream.use { stream ->
XMLSeq.from(stream).windowed().forEach { ... }
}
Tomasz Krakowiak
03/31/2021, 5:23 PMnanodeath
03/31/2021, 5:24 PMonClose
handler...Dennis Tel
03/31/2021, 5:24 PMnanodeath
03/31/2021, 5:26 PMnanodeath
03/31/2021, 5:26 PMTomasz Krakowiak
03/31/2021, 5:32 PMDennis Tel
03/31/2021, 5:33 PMnanodeath
03/31/2021, 5:34 PMTomasz Krakowiak
03/31/2021, 5:35 PMtry(Stream<X> stream = createStream()) {
Iterator<X> iterator = stream.iterator()
consumeIterator(iterator)
} // Stream is automatically closed as created using try-with-resources
Dennis Tel
03/31/2021, 5:40 PMfun <T> processXMLStream(stream: InputStream): Stream<T> {
val reader = XMLInputFactory.newFactory().createXMLStreamReader(stream)
val iterator = object : Iterator<RawProduct> {
override fun next(): RawProduct {
try {
return if (reader.next() == XMLStreamReader.START_ELEMENT && reader.name.toString() == "item") {
xmlMapper.streamValue<Map<String, Any>>(reader).filter { it.value is String } as RawProduct
} else next()
} catch (e: XMLStreamException) {
throw RuntimeException(e);
}
}
override fun hasNext(): Boolean {
return try {
val hasNext = reader.hasNext()
if (!hasNext) reader.close(); // close the stream here
hasNext;
} catch (e: XMLStreamException) {
false;
}
}
};
return ???
}
Dennis Tel
03/31/2021, 5:41 PMnanodeath
03/31/2021, 5:42 PMnanodeath
03/31/2021, 5:43 PMif (!hasNext) reader.close(); // close the stream herealso I'd leave this out of the iterator and tack it onto the stream instead
Tomasz Krakowiak
03/31/2021, 5:44 PMSpliterator<Path> spliterator =
Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED);
return StreamSupport.stream(spliterator, false).onClose{reader.close()};
Something like that : )Dennis Tel
03/31/2021, 5:45 PMDennis Tel
03/31/2021, 5:45 PMfun xmlSequence(stream: InputStream): Sequence<RawProduct> {
val reader = XMLInputFactory.newFactory().createXMLStreamReader(stream)
val iterator = object : Iterator<RawProduct> {
override fun next(): RawProduct = try {
if (reader.next() == XMLStreamReader.START_ELEMENT && reader.name.toString() == "item") {
xmlMapper.streamValue<Map<String, Any>>(reader).filter { it.value is String } as RawProduct
} else next()
} catch (e: XMLStreamException) {
throw RuntimeException(e);
}
override fun hasNext(): Boolean = try {
reader.hasNext()
} catch (e: XMLStreamException) {
false;
}
};
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED),
false
).onClose { reader.close() }.asSequence()
}
Dennis Tel
03/31/2021, 5:46 PMTomasz Krakowiak
03/31/2021, 5:47 PMasSequence
does not close the stream.Dennis Tel
03/31/2021, 5:48 PMasSequence
always a poor choice to use with regards to streams?Tomasz Krakowiak
03/31/2021, 5:50 PMasSequence
method is invalid, as Sequence kdoc clearly states "Sequences can be iterated multiple times" while this is not possible with iterator obtained from stream, the way current implementation does. I think it's kotlin stdlib semantical bug.Tomasz Krakowiak
03/31/2021, 5:50 PM@SinceKotlin("1.2")
public fun <T> Stream<T>.asSequence(): Sequence<T> = Sequence { iterator() }
Dennis Tel
03/31/2021, 5:51 PMSequences can be iterated multiple times, however some sequence implementations might constrain themselves to be iterated only once. That is mentioned specifically in their documentation (e.g. generateSequence overload). The latter sequences throw an exception on an attempt to iterate them the second time.
This doesn’t really say sequences have to be iterable multiple times right?Tomasz Krakowiak
03/31/2021, 5:55 PMDennis Tel
03/31/2021, 5:56 PMDennis Tel
03/31/2021, 5:56 PMDennis Tel
03/31/2021, 5:56 PMTomasz Krakowiak
03/31/2021, 6:04 PMDennis Tel
03/31/2021, 6:04 PMDennis Tel
03/31/2021, 6:05 PMnanodeath
03/31/2021, 6:06 PMUnless you come from Rustthey're all good languages Bront :)
Tomasz Krakowiak
03/31/2021, 6:09 PM