运行时 OSGi 依赖项中的 POJO 忽略导入的 Jackson 注释

Imported Jackson Annotations Ignored for POJOs in OSGi Dependency at Runtime

总结

当 POJO 在运行时在导入包中序列化时,应用于通过 OSGi 依赖项导出的 POJO 的 Jackson 注释不起作用。如果 POJO 直接放在 using bundle 中,或在单元测试中测试(在任一 bundle 中),一切都会按预期工作。

有谁知道什么可以使运行时序列化在运行时忽略导入 OSGi 包中的 Jackson 注释?


这个问题太长了。我试图创建一个尽可能简单的示例。如果有什么不清楚的地方,请告诉我,我会尽量详细说明。

内容

简化示例:

假设我们想要序列化通过 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
}

运行时环境

导出插件 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 的自己的实例。)

您可以通过两种方式解决此问题:

  1. 将 jackson2 作为单独的包部署到您的 OSGi 容器,并确保您的导入和导出包在相关的 jackson 包上有 Import-Package。最中心的捆绑包是:jackson-annotationsjackson-corejackson-databind。在这种情况下,对两个包中的 jackson2 依赖项使用范围 provided
  2. 从您的一个包中导出 jackson2 包,然后将其导入到另一个包中。这会给您额外的工作来确定和维护要导出的包。在这种情况下,在导出包中对 jackson2 使用范围 compile,在导入包中使用范围 provided