From d386b7ff9c846fee8e4cf1a7222970913a104c40 Mon Sep 17 00:00:00 2001 From: Nathaniel Bauernfeind Date: Sat, 13 Feb 2016 16:43:17 -0500 Subject: [PATCH] Upgrade to Jackson 2.7 branch. All current tests pass. --- build.sbt | 19 ++--- project/build.properties | 1 - .../jackson/module/scala/JacksonModule.scala | 6 +- .../deser/OptionDeserializerModule.scala | 4 +- .../scala/deser/SeqDeserializerModule.scala | 4 +- .../deser/SortedMapDeserializerModule.scala | 5 +- .../deser/SortedSetDeserializerModule.scala | 2 +- .../deser/UnsortedMapDeserializerModule.scala | 5 +- .../UntypedObjectDeserializerModule.scala | 1 + .../scala/introspect/OrderingLocator.scala | 2 +- .../ScalaAnnotationIntrospectorModule.scala | 2 +- .../CollectionLikeTypeModifier.scala | 14 ++-- .../modifiers/MapTypeModifierModule.scala | 17 ++-- .../module/scala/ser/EitherSerializer.scala | 2 +- .../scala/ser/IteratorSerializerModule.scala | 2 +- .../scala/ser/OptionSerializerModule.scala | 78 ++++++++++--------- .../deser/CaseClassDeserializerTest.scala | 4 +- .../scala/deser/PrimitiveContainerTest.scala | 6 +- .../deser/UntypedObjectDeserializerTest.scala | 4 +- .../experimental/ScalaObjectMapperTest.scala | 4 +- .../introspect/BeanIntrospectorTest.scala | 12 +-- .../scala/ser/CaseClassSerializerTest.scala | 2 +- .../scala/ser/IterableSerializerTest.scala | 11 ++- .../module/scala/ser/NamingStrategyTest.scala | 2 +- version.sbt | 2 +- 25 files changed, 111 insertions(+), 100 deletions(-) delete mode 100644 project/build.properties diff --git a/build.sbt b/build.sbt index 59f6874e4..31a67935e 100644 --- a/build.sbt +++ b/build.sbt @@ -7,11 +7,12 @@ organization := "com.fasterxml.jackson.module" scalaVersion := "2.11.7" -crossScalaVersions := Seq("2.10.5", "2.11.7") +crossScalaVersions := Seq("2.10.6", "2.11.7") scalacOptions ++= Seq("-deprecation", "-unchecked", "-feature") -scalacOptions in (Compile, compile) += "-Xfatal-warnings" +// Temporarily disable warnings as fatal until migrate Option to new features. +//scalacOptions in (Compile, compile) += "-Xfatal-warnings" // Ensure jvm 1.6 for java lazy val java6Home = new File(System.getenv("JAVA6_HOME")) @@ -27,14 +28,14 @@ scalacOptions += "-target:jvm-1.6" libraryDependencies ++= Seq( "org.scala-lang" % "scala-reflect" % scalaVersion.value, - "com.fasterxml.jackson.core" % "jackson-core" % "2.6.3", - "com.fasterxml.jackson.core" % "jackson-annotations" % "2.6.3", - "com.fasterxml.jackson.core" % "jackson-databind" % "2.6.3", - "com.fasterxml.jackson.module" % "jackson-module-paranamer" % "2.6.3", + "com.fasterxml.jackson.core" % "jackson-core" % "2.7.2", + "com.fasterxml.jackson.core" % "jackson-annotations" % "2.7.2", + "com.fasterxml.jackson.core" % "jackson-databind" % "2.7.2", + "com.fasterxml.jackson.module" % "jackson-module-paranamer" % "2.7.2", // test dependencies - "com.fasterxml.jackson.datatype" % "jackson-datatype-joda" % "2.6.3" % "test", - "com.fasterxml.jackson.datatype" % "jackson-datatype-guava" % "2.6.3" % "test", - "com.fasterxml.jackson.module" % "jackson-module-jsonSchema" % "2.6.3" % "test", + "com.fasterxml.jackson.datatype" % "jackson-datatype-joda" % "2.7.2" % "test", + "com.fasterxml.jackson.datatype" % "jackson-datatype-guava" % "2.7.2" % "test", + "com.fasterxml.jackson.module" % "jackson-module-jsonSchema" % "2.7.2" % "test", "org.scalatest" %% "scalatest" % "2.2.1" % "test", "junit" % "junit" % "4.11" % "test" ) diff --git a/project/build.properties b/project/build.properties deleted file mode 100644 index a6e117b61..000000000 --- a/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=0.13.8 diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/JacksonModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/JacksonModule.scala index eb6e1d7bf..8397ed521 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/JacksonModule.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/JacksonModule.scala @@ -53,7 +53,7 @@ trait JacksonModule extends Module { val MinorVersion = version.getMinorVersion context.getMapperVersion match { case version@VersionExtractor(MajorVersion, minor) if minor < MinorVersion => - throw new JsonMappingException("Jackson version is too old " + version) + throw new JsonMappingException(null, "Jackson version is too old " + version) case version@VersionExtractor(MajorVersion, minor) => // Under semantic versioning, this check would not be needed; however Jackson // occasionally has functionally breaking changes across minor versions @@ -61,10 +61,10 @@ trait JacksonModule extends Module { // depending on implementation details, so for now we'll just declare ourselves // as incompatible and move on. if (minor > MinorVersion) { - throw new JsonMappingException("Incompatible Jackson version: " + version) + throw new JsonMappingException(null, "Incompatible Jackson version: " + version) } case version => - throw new JsonMappingException("Incompatible Jackson version: " + version) + throw new JsonMappingException(null, "Incompatible Jackson version: " + version) } initializers result() foreach (_ apply context) diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/deser/OptionDeserializerModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/deser/OptionDeserializerModule.scala index 0cafb8ac4..e2cc632cc 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/deser/OptionDeserializerModule.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/deser/OptionDeserializerModule.scala @@ -41,7 +41,7 @@ private class OptionDeserializer(elementType: JavaType, p <- Option(property) intr <- Option(ctxt.getAnnotationIntrospector) } yield { - intr.findDeserializationContentType(p.getMember, p.getType) + intr.refineDeserializationType(ctxt.getConfig, p.getMember, p.getType) }).isDefined override def deserialize(jp: JsonParser, ctxt: DeserializationContext) = valueTypeDeser match { @@ -73,7 +73,7 @@ private object OptionDeserializerResolver extends Deserializers.Base { elementValueDeserializer: JsonDeserializer[_]) = if (!OPTION.isAssignableFrom(theType.getRawClass)) null else { - val elementType = theType.containedType(0) + val elementType = theType.getContentType val typeDeser = Option(elementTypeDeserializer).orElse(Option(elementType.getTypeHandler.asInstanceOf[TypeDeserializer])) val valDeser: Option[JsonDeserializer[_]] = Option(elementValueDeserializer).orElse(Option(elementType.getValueHandler)) new OptionDeserializer(elementType, typeDeser, None, valDeser) diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/deser/SeqDeserializerModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/deser/SeqDeserializerModule.scala index 068e0c443..baf3ee1c6 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/deser/SeqDeserializerModule.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/deser/SeqDeserializerModule.scala @@ -27,16 +27,18 @@ private class BuilderWrapper[E](val builder: mutable.Builder[E, _ <: Iterable[E] } private object SeqDeserializer { - val COMPANIONS = new CompanionSorter[collection.Seq]() + val COMPANIONS = new CompanionSorter[collection.Iterable]() .add(IndexedSeq) .add(mutable.ArraySeq) .add(mutable.Buffer) .add(mutable.IndexedSeq) .add(mutable.LinearSeq) .add(mutable.ListBuffer) + .add(mutable.Iterable) .add(mutable.MutableList) .add(mutable.Queue) .add(mutable.ResizableArray) + .add(mutable.Seq) .add(Queue) .add(Stream) .toList diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/deser/SortedMapDeserializerModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/deser/SortedMapDeserializerModule.scala index d30eff6c0..93cf73f07 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/deser/SortedMapDeserializerModule.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/deser/SortedMapDeserializerModule.scala @@ -41,14 +41,14 @@ private class SortedMapDeserializer( with ContextualDeserializer { private val javaContainerType = - config.getTypeFactory.constructMapLikeType(classOf[MapBuilderWrapper[_,_]], collectionType.containedType(0), collectionType.containedType(1)) + config.getTypeFactory.constructMapLikeType(classOf[MapBuilderWrapper[_,_]], collectionType.getKeyType, collectionType.getContentType) private val instantiator = new ValueInstantiator { def getValueTypeDesc = collectionType.getRawClass.getCanonicalName override def canCreateUsingDefault = true override def createUsingDefault(ctx: DeserializationContext) = - new SortedMapBuilderWrapper[AnyRef,AnyRef](SortedMapDeserializer.builderFor(collectionType.getRawClass, collectionType.containedType(0))) + new SortedMapBuilderWrapper[AnyRef,AnyRef](SortedMapDeserializer.builderFor(collectionType.getRawClass, collectionType.getKeyType)) } private val containerDeserializer = @@ -85,7 +85,6 @@ private object SortedMapDeserializerResolver extends Deserializers.Base { elementDeserializer: JsonDeserializer[_]): JsonDeserializer[_] = if (!SORTED_MAP.isAssignableFrom(theType.getRawClass)) null else new SortedMapDeserializer(theType,config,keyDeserializer,elementDeserializer,elementTypeDeserializer) - } /** diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/deser/SortedSetDeserializerModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/deser/SortedSetDeserializerModule.scala index bddab5f76..b514d8626 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/deser/SortedSetDeserializerModule.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/deser/SortedSetDeserializerModule.scala @@ -110,7 +110,7 @@ private object SortedSetDeserializerResolver extends Deserializers.Base { if (!SORTED_SET.isAssignableFrom(rawClass)) null else { val deser = elementDeserializer.asInstanceOf[JsonDeserializer[AnyRef]] - val instantiator = new SortedSetInstantiator(config, rawClass, collectionType.containedType(0)) + val instantiator = new SortedSetInstantiator(config, rawClass, collectionType.getContentType) new SortedSetDeserializer(collectionType, deser, elementTypeDeserializer, instantiator) } } diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala index 5b89642d2..f7c8b5b1e 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala @@ -47,7 +47,7 @@ private class UnsortedMapDeserializer( with ContextualDeserializer { private val javaContainerType = - config.getTypeFactory.constructMapLikeType(classOf[MapBuilderWrapper[_,_]], collectionType.containedType(0), collectionType.containedType(1)) + config.getTypeFactory.constructMapLikeType(classOf[MapBuilderWrapper[_,_]], collectionType.getKeyType, collectionType.getContentType) private val instantiator = new ValueInstantiator { @@ -73,7 +73,7 @@ private class UnsortedMapDeserializer( } override def deserialize(jp: JsonParser, ctxt: DeserializationContext): GenMap[_,_] = { - containerDeserializer.deserialize(jp,ctxt) match { + containerDeserializer.deserialize(jp, ctxt) match { case wrapper: MapBuilderWrapper[_,_] => wrapper.builder.result() } } @@ -96,7 +96,6 @@ private object UnsortedMapDeserializerResolver extends Deserializers.Base { else if (SORTED_MAP.isAssignableFrom(rawClass)) null else new UnsortedMapDeserializer(theType, config, keyDeserializer, elementDeserializer, elementTypeDeserializer) } - } /** diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/deser/UntypedObjectDeserializerModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/deser/UntypedObjectDeserializerModule.scala index 682456183..0b0a5e6ef 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/deser/UntypedObjectDeserializerModule.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/deser/UntypedObjectDeserializerModule.scala @@ -4,6 +4,7 @@ import java.{util => ju} import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.core.`type`.TypeReference +import com.fasterxml.jackson.databind.`type`.{CollectionType, MapType} import com.fasterxml.jackson.databind.deser.{Deserializers, std} import com.fasterxml.jackson.databind.{BeanDescription, DeserializationConfig, DeserializationContext, DeserializationFeature, JavaType, JsonDeserializer} import com.fasterxml.jackson.module.scala.JacksonModule diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/introspect/OrderingLocator.scala b/src/main/scala/com/fasterxml/jackson/module/scala/introspect/OrderingLocator.scala index 6f068ae96..18a3254dd 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/introspect/OrderingLocator.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/introspect/OrderingLocator.scala @@ -24,7 +24,7 @@ object OrderingLocator { val ordering = found.getOrElse { if (matches(classOf[Option[_]])) { - val delegate = locate(javaType.containedType(0)) + val delegate = locate(javaType.getContentType) Ordering.Option(delegate) } else if (matches(classOf[Comparable[_]])) diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/introspect/ScalaAnnotationIntrospectorModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/introspect/ScalaAnnotationIntrospectorModule.scala index b727e1695..f546ba84d 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/introspect/ScalaAnnotationIntrospectorModule.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/introspect/ScalaAnnotationIntrospectorModule.scala @@ -52,7 +52,7 @@ object ScalaAnnotationIntrospector extends NopAnnotationIntrospector private def isScala(a: Annotated): Boolean = { a match { case ac: AnnotatedClass => isMaybeScalaBeanType(ac.getAnnotated) - case am: AnnotatedMember => isMaybeScalaBeanType(am.getContextClass.getAnnotated) + case am: AnnotatedMember => isMaybeScalaBeanType(am.getDeclaringClass) } } diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/modifiers/CollectionLikeTypeModifier.scala b/src/main/scala/com/fasterxml/jackson/module/scala/modifiers/CollectionLikeTypeModifier.scala index 8c528e2d8..ae33f87af 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/modifiers/CollectionLikeTypeModifier.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/modifiers/CollectionLikeTypeModifier.scala @@ -3,17 +3,17 @@ package com.fasterxml.jackson.module.scala.modifiers import java.lang.reflect.Type import com.fasterxml.jackson.databind.JavaType -import com.fasterxml.jackson.databind.`type`.{TypeBindings, TypeFactory, TypeModifier} +import com.fasterxml.jackson.databind.`type`.{CollectionLikeType, TypeBindings, TypeFactory, TypeModifier} private [modifiers] trait CollectionLikeTypeModifier extends TypeModifier with GenTypeModifier { def BASE: Class[_] - override def modifyType(originalType: JavaType, jdkType: Type, context: TypeBindings, typeFactory: TypeFactory) = - if (originalType.containedTypeCount() > 1) originalType else - classObjectFor(jdkType) find BASE.isAssignableFrom map { cls => - val eltType = if (originalType.containedTypeCount() == 1) originalType.containedType(0) else UNKNOWN - typeFactory.constructCollectionLikeType(cls, eltType) - } getOrElse originalType + override def modifyType(originalType: JavaType, jdkType: Type, context: TypeBindings, typeFactory: TypeFactory) = { + if (classObjectFor(jdkType).exists(BASE.isAssignableFrom) && !originalType.isMapLikeType && originalType.containedTypeCount <= 1) { + val valType = originalType.containedTypeOrUnknown(0) + CollectionLikeType.upgradeFrom(originalType, valType) + } else originalType + } } \ No newline at end of file diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/modifiers/MapTypeModifierModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/modifiers/MapTypeModifierModule.scala index aaa1e2454..c38522e2a 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/modifiers/MapTypeModifierModule.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/modifiers/MapTypeModifierModule.scala @@ -2,8 +2,8 @@ package com.fasterxml.jackson.module.scala.modifiers import java.lang.reflect.Type -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.`type`.{TypeBindings, TypeFactory, TypeModifier}; +import com.fasterxml.jackson.databind.JavaType +import com.fasterxml.jackson.databind.`type`.{MapLikeType, TypeBindings, TypeFactory, TypeModifier} import com.fasterxml.jackson.module.scala.JacksonModule @@ -11,12 +11,13 @@ private object MapTypeModifer extends TypeModifier with GenTypeModifier { val BASE = classOf[collection.Map[_,_]] - override def modifyType(originalType: JavaType, jdkType: Type, context: TypeBindings, typeFactory: TypeFactory) = - classObjectFor(jdkType) find (BASE.isAssignableFrom(_)) map { cls => - val keyType = if (originalType.containedTypeCount() >= 1) originalType.containedType(0) else UNKNOWN - val valueType = if (originalType.containedTypeCount() >= 2) originalType.containedType(1) else UNKNOWN - typeFactory.constructMapLikeType(cls, keyType, valueType) - } getOrElse originalType + override def modifyType(originalType: JavaType, jdkType: Type, context: TypeBindings, typeFactory: TypeFactory) = { + if (classObjectFor(jdkType).exists(BASE.isAssignableFrom)) { + val keyType = originalType.containedTypeOrUnknown(0) + val valueType = originalType.containedTypeOrUnknown(1) + MapLikeType.upgradeFrom(originalType, keyType, valueType) + } else originalType + } } diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/ser/EitherSerializer.scala b/src/main/scala/com/fasterxml/jackson/module/scala/ser/EitherSerializer.scala index 96e166dc8..ce8330bb0 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/ser/EitherSerializer.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/ser/EitherSerializer.scala @@ -52,7 +52,7 @@ private class EitherSerializer(elementType: Option[JavaType], } def hasContentTypeAnnotation(provider: SerializerProvider, property: BeanProperty) = Option(property).exists { p => - Option(provider.getAnnotationIntrospector.findSerializationContentType(p.getMember, p.getType)).isDefined + Option(provider.getAnnotationIntrospector.refineSerializationType(provider.getConfig, p.getMember, p.getType)).isDefined } def tryContentSerializer(serializerProvider: SerializerProvider, property: BeanProperty, currentSer: Option[JsonSerializer[_]]) = { diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/ser/IteratorSerializerModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/ser/IteratorSerializerModule.scala index b880abdce..32520e2d0 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/ser/IteratorSerializerModule.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/ser/IteratorSerializerModule.scala @@ -74,7 +74,7 @@ private object ScalaIteratorSerializerResolver extends Serializers.Base { val rawClass = collectionType.getRawClass if (!classOf[collection.Iterator[Any]].isAssignableFrom(rawClass)) null else - new UnresolvedIteratorSerializer(rawClass, collectionType.containedType(0), false, elementTypeSerializer, elementSerializer) + new UnresolvedIteratorSerializer(rawClass, collectionType.getContentType, false, elementTypeSerializer, elementSerializer) } } diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/ser/OptionSerializerModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/ser/OptionSerializerModule.scala index 427f588ec..57ec75495 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/ser/OptionSerializerModule.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/ser/OptionSerializerModule.scala @@ -10,15 +10,14 @@ import databind._ import jsontype.TypeSerializer import jsonschema.{JsonSchema, SchemaAware} import ser.{ContextualSerializer, BeanPropertyWriter, BeanSerializerModifier, Serializers} +import ser.impl.UnknownSerializer import ser.std.StdSerializer -import `type`.CollectionLikeType +import com.fasterxml.jackson.databind.`type`.CollectionLikeType import jsonFormatVisitors.JsonFormatVisitorWrapper import java.lang.reflect.Type import java.{util => ju} -import scala.collection.JavaConverters._ - private class OptionSerializer(elementType: Option[JavaType], valueTypeSerializer: Option[TypeSerializer], beanProperty: Option[BeanProperty], @@ -28,33 +27,41 @@ private class OptionSerializer(elementType: Option[JavaType], with SchemaAware { override def serialize(value: Option[AnyRef], jgen: JsonGenerator, provider: SerializerProvider) { - valueTypeSerializer.map(vt => serializeWithType(value, jgen, provider, vt)).getOrElse { - (value, elementSerializer) match { - case (Some(v: AnyRef), Some(vs)) => vs.serialize(v, jgen, provider) - case (Some(v), _) => - val cls = v.getClass - val ser = if (elementType.exists(_.hasGenericTypes)) - provider.findValueSerializer(provider.constructSpecializedType(elementType.orNull, cls), beanProperty.orNull) - else - provider.findValueSerializer(cls, beanProperty.orNull) - ser.serialize(v, jgen, provider) - - case (None, _) => provider.defaultSerializeNull(jgen) + def doSerialize(v: AnyRef) = { + val cls = v.getClass + val ser = elementType.filter(_.hasGenericTypes) match { + case Some(et) => provider.findValueSerializer(provider.constructSpecializedType(et, cls), beanProperty.orNull) + case None => provider.findValueSerializer(cls, beanProperty.orNull) } + ser.serialize(v, jgen, provider) + } + + valueTypeSerializer match { + case Some(vt) => serializeWithType(value, jgen, provider, vt) + case None => + (value, elementSerializer) match { + case (Some(v), Some(vs: UnknownSerializer)) => doSerialize(v) + case (Some(v), None) => doSerialize(v) + case (Some(v), Some(vs)) => vs.serialize(v, jgen, provider) + case (None, _) => provider.defaultSerializeNull(jgen) + } } } override def serializeWithType(value: Option[AnyRef], jgen: JsonGenerator, provider: SerializerProvider, typeSer: TypeSerializer) { - (value, elementSerializer) match { - case (Some(v: AnyRef), Some(vs)) => vs.serializeWithType(v, jgen, provider, typeSer) - case (Some(v), _) => - val cls = v.getClass - val ser = if (elementType.exists(_.hasGenericTypes)) - provider.findTypedValueSerializer(provider.constructSpecializedType(elementType.orNull, cls), true, beanProperty.orNull) - else - provider.findTypedValueSerializer(cls, true, beanProperty.orNull) - ser.serializeWithType(v, jgen, provider, typeSer) + def doSerialize(v: AnyRef) = { + val cls = v.getClass + val ser = elementType.filter(_.hasGenericTypes) match { + case Some(et) => provider.findTypedValueSerializer(provider.constructSpecializedType(et, cls), true, beanProperty.orNull) + case None => provider.findTypedValueSerializer(cls, true, beanProperty.orNull) + } + ser.serializeWithType(v, jgen, provider, typeSer) + } + (value, elementSerializer) match { + case (Some(v), Some(vs: UnknownSerializer)) => doSerialize(v) + case (Some(v), None) => doSerialize(v) + case (Some(v), Some(vs)) => vs.serializeWithType(v, jgen, provider, typeSer) case (None, _) => provider.defaultSerializeNull(jgen) } } @@ -89,7 +96,7 @@ private class OptionSerializer(elementType: Option[JavaType], def hasContentTypeAnnotation(provider: SerializerProvider, property: BeanProperty) = { Option(property).exists { p => Option(provider.getAnnotationIntrospector).exists { intr => - Option(intr.findSerializationContentType(p.getMember, p.getType)).isDefined + Option(intr.refineSerializationType(provider.getConfig, p.getMember, p.getType)).isDefined } } } @@ -102,7 +109,7 @@ private class OptionSerializer(elementType: Option[JavaType], override def getSchema(provider: SerializerProvider, typeHint: Type, isOptional: Boolean): JsonNode = { val contentSerializer = elementSerializer.getOrElse { val javaType = provider.constructType(typeHint) - val componentType = javaType.containedType(0) + val componentType = javaType.getContentType provider.findTypedValueSerializer(componentType, true, beanProperty.orNull) } contentSerializer match { @@ -112,7 +119,7 @@ private class OptionSerializer(elementType: Option[JavaType], } override def acceptJsonFormatVisitor(wrapper: JsonFormatVisitorWrapper, javaType: JavaType) { - val containedType = javaType.containedType(0) + val containedType = javaType.getContentType val ser = elementSerializer.getOrElse(wrapper.getProvider.findTypedValueSerializer(containedType, true, beanProperty.orNull)) ser.acceptJsonFormatVisitor(wrapper, containedType) } @@ -135,16 +142,13 @@ private object OptionBeanSerializerModifier extends BeanSerializerModifier { override def changeProperties(config: SerializationConfig, beanDesc: BeanDescription, beanProperties: ju.List[BeanPropertyWriter]): ju.List[BeanPropertyWriter] = { - - beanProperties.asScala.transform { w => - if (classOf[Option[_]].isAssignableFrom(w.getPropertyType)) - new OptionPropertyWriter(w) - else - w - }.asJava - + import scala.collection.JavaConversions._ + beanProperties.transform(w => if (isOption(w)) new OptionPropertyWriter(w) else w) } + private[this] def isOption(writer: BeanPropertyWriter): Boolean = { + classOf[Option[_]].isAssignableFrom(writer.getPropertyType) + } } private object OptionSerializerResolver extends Serializers.Base { @@ -160,10 +164,10 @@ private object OptionSerializerResolver extends Serializers.Base { if (!OPTION.isAssignableFrom(`type`.getRawClass)) null else { - val elementType = `type`.containedType(0) + val elementType = `type`.getContentType val typeSer = Option(elementTypeSerializer).orElse(Option(elementType.getTypeHandler.asInstanceOf[TypeSerializer])) val valSer = Option(elementValueSerializer).orElse(Option(elementType.getValueHandler.asInstanceOf[JsonSerializer[AnyRef]])) - new OptionSerializer(Option(`type`.containedType(0)), typeSer, None, valSer) + new OptionSerializer(Option(`type`.getContentType), typeSer, None, valSer) } } diff --git a/src/test/scala/com/fasterxml/jackson/module/scala/deser/CaseClassDeserializerTest.scala b/src/test/scala/com/fasterxml/jackson/module/scala/deser/CaseClassDeserializerTest.scala index e786ae7cb..5bb570cb1 100644 --- a/src/test/scala/com/fasterxml/jackson/module/scala/deser/CaseClassDeserializerTest.scala +++ b/src/test/scala/com/fasterxml/jackson/module/scala/deser/CaseClassDeserializerTest.scala @@ -105,7 +105,7 @@ class CaseClassDeserializerTest extends DeserializerTest { def propertyNamingStrategyMapper = new ObjectMapper() { registerModule(module) - setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES) + setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE) } it should "honor the property naming strategy" in { @@ -115,7 +115,7 @@ class CaseClassDeserializerTest extends DeserializerTest { it should "support serializing into instance var properties" in { val bean = new Bean("ctor") - val reader: ObjectReader = mapper.reader(bean.getClass) + val reader: ObjectReader = mapper.readerFor(bean.getClass) reader.withValueToUpdate(bean).readValue("""{"prop":"readValue"}""") bean.prop should be ("readValue") } diff --git a/src/test/scala/com/fasterxml/jackson/module/scala/deser/PrimitiveContainerTest.scala b/src/test/scala/com/fasterxml/jackson/module/scala/deser/PrimitiveContainerTest.scala index 853ab6ebe..f6b0c5e72 100644 --- a/src/test/scala/com/fasterxml/jackson/module/scala/deser/PrimitiveContainerTest.scala +++ b/src/test/scala/com/fasterxml/jackson/module/scala/deser/PrimitiveContainerTest.scala @@ -12,8 +12,8 @@ object PrimitiveContainerTest case class OptionLong(value: Option[Long]) case class AnnotatedOptionLong(@JsonDeserialize(contentAs = classOf[java.lang.Long]) value: Option[Long]) - case class AnnotatedHashKeyLong(@JsonDeserialize(keyAs = classOf[java.lang.Long]) value: Map[Long,String]) - case class AnnotatedHashValueLong(@JsonDeserialize(contentAs = classOf[java.lang.Long]) value: Map[String,Long]) + case class AnnotatedHashKeyLong(@JsonDeserialize(keyAs = classOf[java.lang.Long]) value: Map[Long, String]) + case class AnnotatedHashValueLong(@JsonDeserialize(contentAs = classOf[java.lang.Long]) value: Map[String, Long]) } @RunWith(classOf[JUnitRunner]) @@ -45,7 +45,7 @@ class PrimitiveContainerTest extends DeserializationFixture thrown.getMessage should startWith ("Numeric value (9223372036854775807) out of range") } - it should "support map keys" ignore { f => + it should "support map keys" in { f => val value = f.readValue[AnnotatedHashKeyLong]("""{"value":{"1":"one"}}""") value.value should contain key 1L value.value(1L) shouldBe "one" diff --git a/src/test/scala/com/fasterxml/jackson/module/scala/deser/UntypedObjectDeserializerTest.scala b/src/test/scala/com/fasterxml/jackson/module/scala/deser/UntypedObjectDeserializerTest.scala index 6c0e4a45f..8f01ff461 100644 --- a/src/test/scala/com/fasterxml/jackson/module/scala/deser/UntypedObjectDeserializerTest.scala +++ b/src/test/scala/com/fasterxml/jackson/module/scala/deser/UntypedObjectDeserializerTest.scala @@ -3,7 +3,7 @@ package com.fasterxml.jackson.module.scala.deser import com.fasterxml.jackson.module.scala.{JacksonModule, DefaultScalaModule} import com.fasterxml.jackson.databind.{ObjectMapper, DeserializationConfig, JavaType, AbstractTypeResolver} import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper -import com.fasterxml.jackson.databind.`type`.MapLikeType +import com.fasterxml.jackson.databind.`type`.{TypeFactory, MapLikeType} class UntypedObjectDeserializerTest extends DeserializerTest { def module = DefaultScalaModule @@ -29,7 +29,7 @@ class UntypedObjectDeserializerTest extends DeserializerTest { val result = Some(javaType) collect { case mapLikeType: MapLikeType => if (javaType.getRawClass.equals(classOf[collection.Map[_,_]])) { - javaType.narrowBy(classOf[collection.immutable.TreeMap[_,_]]) + TypeFactory.defaultInstance().constructSpecializedType(javaType, classOf[collection.immutable.TreeMap[_,_]]) } else null } result.orNull diff --git a/src/test/scala/com/fasterxml/jackson/module/scala/experimental/ScalaObjectMapperTest.scala b/src/test/scala/com/fasterxml/jackson/module/scala/experimental/ScalaObjectMapperTest.scala index 7ad929641..a98661d9a 100644 --- a/src/test/scala/com/fasterxml/jackson/module/scala/experimental/ScalaObjectMapperTest.scala +++ b/src/test/scala/com/fasterxml/jackson/module/scala/experimental/ScalaObjectMapperTest.scala @@ -129,12 +129,12 @@ class ScalaObjectMapperTest extends FlatSpec with Matchers { } it should "produce reader with type" in { - val result = mapper.reader[GenericTestClass[Int]].readValue(genericJson).asInstanceOf[GenericTestClass[Int]] + val result = mapper.readerFor[GenericTestClass[Int]].readValue(genericJson).asInstanceOf[GenericTestClass[Int]] result should equal(genericInt) } it should "produce reader with view" in { - val reader = mapper.readerWithView[PublicView].withType(classOf[Target]) + val reader = mapper.readerWithView[PublicView].forType(classOf[Target]) val result = reader.readValue("""{"foo":"foo","bar":42}""").asInstanceOf[Target] result should equal(Target.apply("foo", 0)) } diff --git a/src/test/scala/com/fasterxml/jackson/module/scala/introspect/BeanIntrospectorTest.scala b/src/test/scala/com/fasterxml/jackson/module/scala/introspect/BeanIntrospectorTest.scala index ee5d22bae..57235443d 100644 --- a/src/test/scala/com/fasterxml/jackson/module/scala/introspect/BeanIntrospectorTest.scala +++ b/src/test/scala/com/fasterxml/jackson/module/scala/introspect/BeanIntrospectorTest.scala @@ -1,13 +1,15 @@ package com.fasterxml.jackson.module.scala.introspect +import java.lang.reflect.Member + +import com.fasterxml.jackson.module.scala.BaseSpec import com.fasterxml.jackson.module.scala.introspect.BeanIntrospectorTest.DecodedNameMatcher import org.junit.runner.RunWith import org.scalatest.junit.JUnitRunner -import org.scalatest.{Inside, OptionValues, LoneElement, FlatSpec} -import org.scalatest.matchers.{HavePropertyMatcher, HavePropertyMatchResult, ShouldMatchers} -import reflect.NameTransformer -import com.fasterxml.jackson.module.scala.BaseSpec -import java.lang.reflect.Member +import org.scalatest.matchers.{HavePropertyMatchResult, HavePropertyMatcher} +import org.scalatest.{Inside, LoneElement, OptionValues} + +import scala.reflect.NameTransformer object BeanIntrospectorTest { diff --git a/src/test/scala/com/fasterxml/jackson/module/scala/ser/CaseClassSerializerTest.scala b/src/test/scala/com/fasterxml/jackson/module/scala/ser/CaseClassSerializerTest.scala index 17fe8ed37..80e958454 100644 --- a/src/test/scala/com/fasterxml/jackson/module/scala/ser/CaseClassSerializerTest.scala +++ b/src/test/scala/com/fasterxml/jackson/module/scala/ser/CaseClassSerializerTest.scala @@ -134,7 +134,7 @@ class CaseClassSerializerTest extends SerializerTest { def propertyNamingStrategyMapper = new ObjectMapper() { registerModule(module) - setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES) + setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE) } it should "honor the property naming strategy" in { diff --git a/src/test/scala/com/fasterxml/jackson/module/scala/ser/IterableSerializerTest.scala b/src/test/scala/com/fasterxml/jackson/module/scala/ser/IterableSerializerTest.scala index 2baff404e..72f4d7956 100644 --- a/src/test/scala/com/fasterxml/jackson/module/scala/ser/IterableSerializerTest.scala +++ b/src/test/scala/com/fasterxml/jackson/module/scala/ser/IterableSerializerTest.scala @@ -73,10 +73,8 @@ class IterableSerializerTest extends SerializerTest { serialize(mutable.LinkedHashSet(1,2,3)) should matchUnorderedSet } - it should "not serialize a Map[Int]" ignore { - intercept[JsonMappingException] { - serialize(Map(1->2,3->4)) - } + it should "serialize a Map[Int]" in { + serialize(Map(1->2,3->4)) should matchUnorderedMap } it should "honor the JsonInclude(NON_EMPTY) annotation" in { @@ -95,4 +93,9 @@ class IterableSerializerTest extends SerializerTest { be ("[3,1,2]") or be ("[3,2,1]") } + + val matchUnorderedMap = { + be ("{\"1\":2,\"3\":4}") or + be ("{\"3\":4,\"1\":2}") + } } diff --git a/src/test/scala/com/fasterxml/jackson/module/scala/ser/NamingStrategyTest.scala b/src/test/scala/com/fasterxml/jackson/module/scala/ser/NamingStrategyTest.scala index 56d1f9600..f92f16893 100644 --- a/src/test/scala/com/fasterxml/jackson/module/scala/ser/NamingStrategyTest.scala +++ b/src/test/scala/com/fasterxml/jackson/module/scala/ser/NamingStrategyTest.scala @@ -25,7 +25,7 @@ class NamingStrategyTest extends fixture.FlatSpec with Matchers { protected def withFixture(test: OneArgTest): Outcome = { val mapper = new ObjectMapper() mapper.registerModule(DefaultScalaModule) - mapper.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES) + mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE) test(mapper) } diff --git a/version.sbt b/version.sbt index 6f57b506f..f1dd76872 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -version in ThisBuild := "2.6.4-SNAPSHOT" \ No newline at end of file +version in ThisBuild := "2.7.2-SNAPSHOT"