diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/ser/IterableSerializerModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/ser/IterableSerializerModule.scala index e13bbcc54..139ee1a80 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/ser/IterableSerializerModule.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/ser/IterableSerializerModule.scala @@ -7,24 +7,22 @@ import java.{lang => jl} import com.fasterxml.jackson.core.JsonGenerator import com.fasterxml.jackson.databind.`type`.CollectionLikeType import com.fasterxml.jackson.databind.jsontype.TypeSerializer -import com.fasterxml.jackson.databind.ser.std.{AsArraySerializerBase, CollectionSerializer} +import com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase import com.fasterxml.jackson.databind.ser.{ContainerSerializer, Serializers} import com.fasterxml.jackson.databind._ import com.fasterxml.jackson.module.scala.modifiers.IterableTypeModifierModule -import scala.collection.JavaConverters._ - private trait IterableSerializer extends AsArraySerializerBase[collection.Iterable[Any]] { - def collectionSerializer: CollectionSerializer + def collectionSerializer: ScalaIterableSerializer override def hasSingleElement(value: collection.Iterable[Any]): Boolean = { value.size == 1 } override def serializeContents(value: collection.Iterable[Any], gen: JsonGenerator, provider: SerializerProvider): Unit = { - collectionSerializer.serializeContents(value.asJavaCollection, gen, provider) + collectionSerializer.serializeContents(value, gen, provider) } override def withResolved(property: BeanProperty, @@ -45,7 +43,7 @@ private class ResolvedIterableSerializer( src: IterableSerializer, with IterableSerializer { val collectionSerializer = - new CollectionSerializer(src.collectionSerializer, property, vts, elementSerializer, unwrapSingle) + new ScalaIterableSerializer(src.collectionSerializer, property, vts, elementSerializer) override def _withValueTypeSerializer(newVts: TypeSerializer): ContainerSerializer[_] = new ResolvedIterableSerializer(this, property, newVts, elementSerializer, unwrapSingle) @@ -61,7 +59,7 @@ private class UnresolvedIterableSerializer( cls: Class[_], with IterableSerializer { val collectionSerializer = - new CollectionSerializer(et, staticTyping, vts, elementSerializer) + new ScalaIterableSerializer(et, staticTyping, vts, elementSerializer) override def _withValueTypeSerializer(newVts: TypeSerializer): ContainerSerializer[_] = new UnresolvedIterableSerializer(cls, et, staticTyping, newVts, elementSerializer) diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/ser/ScalaIterableSerializer.scala b/src/main/scala/com/fasterxml/jackson/module/scala/ser/ScalaIterableSerializer.scala new file mode 100644 index 000000000..d2025bf6d --- /dev/null +++ b/src/main/scala/com/fasterxml/jackson/module/scala/ser/ScalaIterableSerializer.scala @@ -0,0 +1,101 @@ +package com.fasterxml.jackson.module.scala.ser + +import java.{lang => jl} + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.databind.jsontype.TypeSerializer +import com.fasterxml.jackson.databind.ser.ContainerSerializer +import com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase +import com.fasterxml.jackson.databind.{BeanProperty, JavaType, JsonSerializer, SerializationFeature, SerializerProvider} + +case class ScalaIterableSerializer(elemType: JavaType, staticTyping: Boolean, vts: TypeSerializer, + property: BeanProperty, valueSerializer: JsonSerializer[Object]) + extends AsArraySerializerBase[collection.Iterable[Any]](collection.Iterable.getClass, elemType, staticTyping, vts, property, valueSerializer) { + + def this(elemType: JavaType, staticTyping: Boolean, vts: TypeSerializer, valueSerializer: JsonSerializer[Object]) { + this(elemType, staticTyping, vts, None.orNull, valueSerializer.asInstanceOf[JsonSerializer[Object]]) + } + + def this(src: ScalaIterableSerializer, property: BeanProperty, vts: TypeSerializer, valueSerializer: JsonSerializer[_]) { + this(src.elemType, src.staticTyping, vts, property, valueSerializer.asInstanceOf[JsonSerializer[Object]]) + } + + override def isEmpty(prov: SerializerProvider, value: Iterable[Any]): Boolean = value.isEmpty + + override def hasSingleElement(value: Iterable[Any]): Boolean = value.size == 1 + + override def serialize(value: Iterable[Any], g: JsonGenerator, provider: SerializerProvider): Unit = { + val len: Int = value.size + if (len == 1 && + (_unwrapSingle == null && provider.isEnabled(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED)) || (_unwrapSingle)) { + serializeContents(value, g, provider) + } else { + g.writeStartArray(value, len) + serializeContents(value, g, provider) + g.writeEndArray() + } + } + + override def serializeContents(value: Iterable[Any], g: JsonGenerator, provider: SerializerProvider): Unit = { + g.setCurrentValue(value) + if (_elementSerializer != null) { + serializeContentsUsing(value, g, provider, _elementSerializer) + } else { + val it = value.iterator + if (it.hasNext) { + val typeSer = _valueTypeSerializer + var serializers = _dynamicSerializers + var i = 0 + try do { + val elem = it.next + if (elem == null) provider.defaultSerializeNull(g) + else { + val cc = elem.getClass + var serializer = serializers.serializerFor(cc) + if (serializer == null) { + if (_elementType.hasGenericTypes) serializer = _findAndAddDynamic(serializers, provider.constructSpecializedType(_elementType, cc), provider) + else serializer = _findAndAddDynamic(serializers, cc, provider) + serializers = _dynamicSerializers + } + if (typeSer == null) serializer.serialize(elem.asInstanceOf[Object], g, provider) + else serializer.serializeWithType(elem.asInstanceOf[Object], g, provider, typeSer) + } + i += 1 + } while (it.hasNext) + catch { + case e: Exception => + wrapAndThrow(provider, e, value, i) + } + } + } + } + + override def withResolved(property: BeanProperty, vts: TypeSerializer, elementSerializer: JsonSerializer[_], + unwrapSingle: jl.Boolean): AsArraySerializerBase[Iterable[Any]] = { + new ScalaIterableSerializer(this, property, vts, elementSerializer) + } + + override def _withValueTypeSerializer(vts: TypeSerializer): ContainerSerializer[_] = { + new ScalaIterableSerializer(this, _property, vts, _elementSerializer) + } + + private def serializeContentsUsing(value: Iterable[Any], g: JsonGenerator, provider: SerializerProvider, ser: JsonSerializer[AnyRef]): Unit = { + val it = value.iterator + if (it.hasNext) { + val typeSer = _valueTypeSerializer + var i = 0 + do { + val elem = it.next + try { + if (elem == null) provider.defaultSerializeNull(g) + else if (typeSer == null) ser.serialize(elem.asInstanceOf[Object], g, provider) + else ser.serializeWithType(elem.asInstanceOf[Object], g, provider, typeSer) + i += 1 + } catch { + case e: Exception => + wrapAndThrow(provider, e, value, i) + } + } while (it.hasNext) + } + } +} \ No newline at end of file