运行时 OSGi 依赖项中的 POJO 忽略导入的 Jackson 注释
Imported Jackson Annotations Ignored for POJOs in OSGi Dependency at Runtime
总结
当 POJO 在运行时在导入包中序列化时,应用于通过 OSGi 依赖项导出的 POJO 的 Jackson 注释不起作用。如果 POJO 直接放在 using bundle 中,或在单元测试中测试(在任一 bundle 中),一切都会按预期工作。
有谁知道什么可以使运行时序列化在运行时忽略导入 OSGi 包中的 Jackson 注释?
这个问题太长了。我试图创建一个尽可能简单的示例。如果有什么不清楚的地方,请告诉我,我会尽量详细说明。
内容
内部导出包
- POJO
- 单元测试(有效)
- 运行时测试(有效)
内部导入包
- 单元测试(有效)
- 运行时测试(失败)
运行时环境详细信息
- 捆绑清单(简化)
简化示例:
假设我们想要序列化通过 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)
- 行家 3.2.1
- Java1.8
- 杰克逊 2.9.3
导出插件 Bundle Manifest(简化)
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
导入插件 Bundle Manifest(简化)
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
-注释在导入依赖项 的运行时被忽略,但其他一切都按预期工作。同样,我不认为这是 Jackson 版本的问题,尽管我可能忽略了一些东西。
我是否可能错过了一些基本的 OSGi 行为?
根据我的评论和您的反馈:
问题是您的两个包具有不同的 Jackson 注释实例 classes。当 Jackson 框架扫描 classes 中的注释时,它会查找它使用的特定注释 class 实例。如果一个 bundle 有自己的相同 class 实例,则注释将不会被识别。 (在 OSGi 中,每个 bundle 都有一个单独的 class 加载器,每个 class 加载器可以包含给定 class 的自己的实例。)
您可以通过两种方式解决此问题:
- 将 jackson2 作为单独的包部署到您的 OSGi 容器,并确保您的导入和导出包在相关的 jackson 包上有
Import-Package
。最中心的捆绑包是:jackson-annotations
、jackson-core
和 jackson-databind
。在这种情况下,对两个包中的 jackson2 依赖项使用范围 provided
。
- 从您的一个包中导出 jackson2 包,然后将其导入到另一个包中。这会给您额外的工作来确定和维护要导出的包。在这种情况下,在导出包中对 jackson2 使用范围
compile
,在导入包中使用范围 provided
。
总结
当 POJO 在运行时在导入包中序列化时,应用于通过 OSGi 依赖项导出的 POJO 的 Jackson 注释不起作用。如果 POJO 直接放在 using bundle 中,或在单元测试中测试(在任一 bundle 中),一切都会按预期工作。
有谁知道什么可以使运行时序列化在运行时忽略导入 OSGi 包中的 Jackson 注释?
这个问题太长了。我试图创建一个尽可能简单的示例。如果有什么不清楚的地方,请告诉我,我会尽量详细说明。
内容
内部导出包
- POJO
- 单元测试(有效)
- 运行时测试(有效)
内部导入包
- 单元测试(有效)
- 运行时测试(失败)
运行时环境详细信息
- 捆绑清单(简化)
简化示例:
假设我们想要序列化通过 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)
- 行家 3.2.1
- Java1.8
- 杰克逊 2.9.3
导出插件 Bundle Manifest(简化)
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
导入插件 Bundle Manifest(简化)
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
-注释在导入依赖项 的运行时被忽略,但其他一切都按预期工作。同样,我不认为这是 Jackson 版本的问题,尽管我可能忽略了一些东西。
我是否可能错过了一些基本的 OSGi 行为?
根据我的评论和您的反馈:
问题是您的两个包具有不同的 Jackson 注释实例 classes。当 Jackson 框架扫描 classes 中的注释时,它会查找它使用的特定注释 class 实例。如果一个 bundle 有自己的相同 class 实例,则注释将不会被识别。 (在 OSGi 中,每个 bundle 都有一个单独的 class 加载器,每个 class 加载器可以包含给定 class 的自己的实例。)
您可以通过两种方式解决此问题:
- 将 jackson2 作为单独的包部署到您的 OSGi 容器,并确保您的导入和导出包在相关的 jackson 包上有
Import-Package
。最中心的捆绑包是:jackson-annotations
、jackson-core
和jackson-databind
。在这种情况下,对两个包中的 jackson2 依赖项使用范围provided
。 - 从您的一个包中导出 jackson2 包,然后将其导入到另一个包中。这会给您额外的工作来确定和维护要导出的包。在这种情况下,在导出包中对 jackson2 使用范围
compile
,在导入包中使用范围provided
。