摘要
当 POJO 在运行时在导入捆绑包中序列化时,应用于通过 OSGi depdendency 导出的 POJO 的杰克逊注释不起作用。如果将 POJO 直接放置在使用捆绑包中,或在单元测试中进行测试(在任一捆绑包中(,则一切按预期工作。
有谁知道什么会使运行时序列化在导入 OSGi 捆绑包中忽略运行时的杰克逊注释?
这是一个悬而未决的问题。我试图创建一个尽可能简单的例子。如果有什么不清楚的地方,请告诉我,我会尽力详细说明。
内容
-
导出捆绑包内部
- 波乔
- 单元测试(有效(
- 运行时测试(有效(
-
导入捆绑包内部
- 单元测试(有效(
- 运行时测试(失败(
-
运行时环境详细信息
- 捆绑清单(简化(
简化示例:
假设我们想序列化一个通过OSGi导出和导入的简单POJO。JSON 注释应该在导入和导出捆绑包中工作,无论是运行时还是在单元测试期间(运行时在导入时失败(。
导出捆绑包内部:
Jackson 序列化的运行时测试和单元测试在声明 POJO 本身的捆绑包中都可以正常工作。
要序列化的 POJO
@JsonProperty
注释应该使此 POJO 的任何序列化版本看起来像{"correctSerializedName":"someName"}
而不是{"javaName":"someName"}
:
package exporting.osgi.bundle.models;
import com.fasterxml.jackson.annotation.JsonProperty;
public class DependencyModel {
private String javaName;
@JsonProperty("correctSerializedName")
public String getJavaName() {
return javaName;
}
public DependencyModel(String javaName) {
this.javaName = javaName;
}
}
正确行为:单元测试
import com.fasterxml.jackson.*;
import org.junit.jupiter.*;
class ExportingBundleTests {
@Test
void serialize_inDepdendencyProject_getsCorrectJsonName() {
DependencyModel dependencyModel = new DependencyModel("name");
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(dependencyModel);
// Asserts True -> serialization works as expected
assertEquals(jsonString, "{"correctSerializedName":"name"}");
}
}
正确行为:运行时
public void runtimeFromDepdendency() {
DependencyModel dependencyModel = new DependencyModel("name");
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(dependencyModel);
// jsonString = {"correctSerializedName":"name"}
}
在导入 OSGi 捆绑包内部
正确行为:单元测试
import exporting.osgi.bundle.models.DependencyModel;
import com.fasterxml.jackson.*;
import org.junit.jupiter.api.*;
class ImportingBundleTests {
@Test
void serialize_inUsingProject_getsCorrectJsonName() {
DependencyModel dependencyModel = new DependencyModel("name");
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(dependencyModel);
// Asserts True -> serialization works as expected
assertEquals(jsonString, "{"correctSerializedName":"name"}");
}
}
失败:运行时
import exporting.osgi.bundle.models.DependencyModel;
import com.fasterxml.jackson.*;
public Response runsFromUsingProject() throws JsonProcessingException {
DependencyModel dependencyModel = new DependencyModel("name");
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(dependencyModel);
// jsonString = {"javaName":"name"} <---- WHICH IS WRONG
}
运行时环境
- Jira 7.2.2 OSGi(基于 Apache Felix(
- Maven 3.2.1
- 爪哇 1.8
- 杰克逊 2.9.3
导出插件捆绑包清单(简化(
Created-By: Apache Maven Bundle Plugin
Manifest-Version: 1.0
Build-Jdk: 1.8.0_111
Bundle-ManifestVersion: 2
Export-Package:
...
exporting.osgi.bundle;version="1.0.0";
uses:="exporting.osgi.bundle.models",
...
Originally-Created-By: Apache Maven Bundle Plugin
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Spring-Context: *
Tool: Bnd-2.4.1.201501161923
导入插件捆绑包清单(简化(
Created-By: Apache Maven Bundle Plugin
Manifest-Version: 1.0
Build-Jdk: 1.8.0_111
Bundle-ManifestVersion: 2
Archiver-Version: Plexus Archiver
Bundle-ClassPath: .,META-INF/lib/gt-epsg-hsql-18.1.jar,META-INF/lib/sq
lite-jdbc-3.8.11.1.jar
Import-Package:
...
exporting.osgi.bundle.models
...
com.fasterxml.jackson.dataformat.xml;resolution:=optional,
com.fasterxml.jackson.dataformat.xml.deser;resolution:=optional,
com.fasterxml.jackson.dataformat.xml.ser;resolution:=optional,
org.codehaus.jackson;resolution:=optional,
org.codehaus.jackson.annotate;resolution:=optional,
org.codehaus.jackson.map;resolution:=optional,
org.codehaus.jackson.map.annotate;resolution:=optional,
...
Originally-Created-By: Apache Maven Bundle Plugin
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Spring-Context: *
Tool: Bnd-2.4.1.201501161923
如上所示,@JsonProperty
-注释在导入过程中在运行时被忽略,但其他所有内容都按预期工作。同样,我不认为这是杰克逊版本的问题,尽管我可能忽略了一些东西。
我是否错过了一些基本的OSGi行为?
根据我的评论和您的反馈:
问题是您的两个捆绑包具有不同的杰克逊注释类实例。当 Jackson 框架扫描类以查找批注时,它会查找它使用的特定批注类实例。如果捆绑包具有同一类的自己的实例,则不会识别注释。(在OSGi中,每个捆绑包都有一个单独的类加载器,每个类加载器可以包含给定类的自己的实例。
您可以通过两种方式解决此问题:
- 将 jackson2 作为单独的捆绑包部署到 OSGi 容器中,并确保导入和导出捆绑包都
Import-Package
相关的 jackson 包。最核心的捆绑包是:jackson-annotations
、jackson-core
和jackson-databind
。在这种情况下,请对两个捆绑包中的 jackson2 依赖项使用范围provided
。
从其中一个捆绑包中 - 导出 jackson2 包,并将其导入到另一个捆绑包中。这将为您提供额外的工作,以确定和维护要导出的包。在这种情况下,请在导出捆绑包中使用 jackson2 的作用域
compile
,在导入捆绑包中使用作用域provided
。
就我而言,有杰克逊的进口,我没有考虑到。看到您的评论后,我只是将它们添加到pom中。它工作得很好。