-
Notifications
You must be signed in to change notification settings - Fork 155
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
spline #1155 Fix ArangoJack deserialization of generic types
- Loading branch information
Showing
10 changed files
with
206 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
commons/src/main/scala/com/fasterxml/jackson/core/type/package.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
* Copyright 2024 ABSA Group Limited | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.fasterxml.jackson.core | ||
|
||
package object `type` { | ||
object TypeReference { | ||
implicit val typeRefBoolean: TypeReference[Boolean] = new TypeReference[Boolean] {} | ||
implicit val typeRefUnit: TypeReference[Nothing] = new TypeReference[Nothing] {} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
persistence/src/main/scala/com/arangodb/util/TypeRefAwareArangoDeserializerDecor.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
* Copyright 2024 ABSA Group Limited | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.arangodb.util | ||
|
||
import com.arangodb.velocypack.VPackSlice | ||
import com.fasterxml.jackson.core.`type`.TypeReference | ||
import com.fasterxml.jackson.databind.ObjectMapper | ||
import za.co.absa.commons.reflect.ReflectionUtils | ||
|
||
import java.lang.reflect.Type | ||
|
||
/** | ||
* This is a workaround for a ArangoJack deserializer limitation. | ||
* The ArangoJack serde being a wrapper over the Jackson serde needs to be able to take a `TypeReference` instance | ||
* and pass it over to Jackson in order to deserialize generic entities. This is not possible in the current ArangoJack version. | ||
* Hence, we have to add another method that we'd use to pass the type reference instance to the ArrangoJack's underlying Jackson | ||
* mapper directly, bypassing the ArangoJack's public API. | ||
*/ | ||
class TypeRefAwareArangoDeserializerDecor(deserializer: ArangoDeserializer) extends ArangoDeserializer { | ||
private lazy val vpackMapper: ObjectMapper = ReflectionUtils.extractValue[ObjectMapper](deserializer, "vpackMapper") | ||
|
||
def deserialize[A](vpack: VPackSlice)(implicit typeRef: TypeReference[A]): A = { | ||
val aType = typeRef.getType | ||
if (aType == classOf[String]) { | ||
deserializer.deserialize[A](vpack, aType) | ||
} else { | ||
vpackMapper.readValue(vpack.getBuffer, vpack.getStart, vpack.getStart + vpack.getByteSize, typeRef) | ||
} | ||
} | ||
|
||
override def deserialize[T](vpack: VPackSlice, aType: Type): T = deserializer.deserialize[T](vpack, aType) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
persistence/src/test/scala/com/arangodb/util/TypeRefAwareArangoDeserializerDecorSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
/* | ||
* Copyright 2024 ABSA Group Limited | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.arangodb.util | ||
|
||
import com.arangodb.mapping.ArangoJack | ||
import com.arangodb.util.TypeRefAwareArangoDeserializerDecorSpec._ | ||
import com.arangodb.velocypack.{VPackParser, VPackSlice} | ||
import com.fasterxml.jackson.core.`type`.TypeReference | ||
import com.fasterxml.jackson.module.scala.DefaultScalaModule | ||
import org.mockito.Mockito.{verify, verifyNoMoreInteractions} | ||
import org.scalatest.flatspec.AnyFlatSpec | ||
import org.scalatest.matchers.should.Matchers | ||
import org.scalatestplus.mockito.MockitoSugar.mock | ||
|
||
import java.lang.reflect.Type | ||
import scala.reflect.ClassTag | ||
|
||
class TypeRefAwareArangoDeserializerDecorSpec extends AnyFlatSpec with Matchers { | ||
|
||
private val vpackParser = new VPackParser.Builder().build | ||
|
||
behavior of "deserialize(VPackSlice, Type) method" | ||
|
||
it should "delegate to underlying ArangoJack deserializer unconditionally" in { | ||
val dummyVPack = mock[VPackSlice] | ||
val dummyType = mock[Type] | ||
val mockArangoDeserializer = mock[ArangoDeserializer] | ||
val deserializerDecorator = new TypeRefAwareArangoDeserializerDecor(mockArangoDeserializer) | ||
|
||
deserializerDecorator.deserialize(dummyVPack, dummyType) | ||
|
||
verify(mockArangoDeserializer).deserialize(dummyVPack, dummyType) | ||
verifyNoMoreInteractions(mockArangoDeserializer) | ||
} | ||
|
||
behavior of "deserialize(VPackSlice, TypeReference) method" | ||
|
||
it should "delegate string types to the underlying deserializer" in { | ||
val dummyVPack = mock[VPackSlice] | ||
val stringTypeRef = new TypeReference[String] {} | ||
val mockArangoDeserializer = mock[ArangoDeserializer] | ||
val deserializerDecorator = new TypeRefAwareArangoDeserializerDecor(mockArangoDeserializer) | ||
|
||
deserializerDecorator.deserialize(dummyVPack)(stringTypeRef) | ||
|
||
verify(mockArangoDeserializer).deserialize(dummyVPack, classOf[String]) | ||
verifyNoMoreInteractions(mockArangoDeserializer) | ||
} | ||
|
||
it should "deserialize generic types" in { | ||
val arangoJack = new ArangoJack { | ||
configure(mapper => mapper.registerModule(new DefaultScalaModule)) | ||
} | ||
val deserializerDecorator = new TypeRefAwareArangoDeserializerDecor(arangoJack) | ||
|
||
val result = deserializerDecorator.deserialize[GenericContainer[Blah]](vpackParser.fromJson( | ||
""" | ||
|{ | ||
| "offset": 42, | ||
| "totalCount": 777, | ||
| "item": {"a": 0, "b": "bbb"}, | ||
| "items": [ | ||
| {"a": 111, "b": "foo"}, | ||
| {"a": 222, "b": "bar"} | ||
| ] | ||
|} | ||
|""".stripMargin | ||
)) | ||
|
||
result shouldEqual GenericContainer( | ||
item = Blah(0, "bbb"), | ||
items = Seq(Blah(111, "foo"), Blah(222, "bar")) | ||
) | ||
} | ||
} | ||
|
||
object TypeRefAwareArangoDeserializerDecorSpec { | ||
implicit val typeRef: TypeReference[GenericContainer[Blah]] = new TypeReference[GenericContainer[Blah]]() {} | ||
|
||
case class GenericContainer[T: ClassTag]( | ||
items: Seq[T], | ||
item: T | ||
) | ||
|
||
case class Blah(a: Int, b: String) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters