Reputation: 3676
Jackson annotations applied to POJOs exported through an OSGi depdendency does not work when the POJO is serialized in an importing bundle at Runtime. If the POJO is placed in the using bundle directly, or tested in a Unit Test (in either bundle), everything works as expected.
Does anyone know what could make the runtime serialization ignore the Jackson-annotations at runtime in the importing OSGi-bundle?
This is a looong question. I have tried to create an as simple example as possible. If anything is unclear, please let me know, and I will try to elaborate.
Contents
Inside Exporting Bundle
Inside Importing Bundle
Runtime environment details
Let's assume we have want to serialize a simple POJO exported and imported over OSGi. The JSON-annotations should work both in the importing and exporting bundle, both runtime and during unit tests (runtime fails in the when imported).
Both runtime and unit tests of the Jackson serialization works just fine in the bundle where the POJO itself is declared.
POJO to serialize
The @JsonProperty
-annotation should make any serialized version of this POJO look something like {"correctSerializedName":"someName"}
and not {"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;
}
}
Correct behaviour: Unit test
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\"}");
}
}
Correct behaviour: Runtime
public void runtimeFromDepdendency() {
DependencyModel dependencyModel = new DependencyModel("name");
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(dependencyModel);
// jsonString = {"correctSerializedName":"name"}
}
Correct behaviour: Unit test
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\"}");
}
}
FAILS: Runtime
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
}
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
As illustrated above, the @JsonProperty
-annotation is ignored at runtime in the importing depdendency, but everything else works as expected. Again, I don't think this is a Jackson-version issue, although I might have overlooked something.
Have I perhaps missed some fundamental OSGi-behaviour?
Upvotes: 4
Views: 1143
Reputation: 1
In my case there were Jackson imports that I wasn't taking into account. I just added them in the pom after I saw your comment. It worked perfectly.
Upvotes: 0
Reputation: 4711
Based on my comments and your feedback:
The problem is that your two bundles have different instances of the Jackson annotation classes. When the Jackson framework scans classes for annotations, it looks for the specific annotation class instance that it uses. If a bundle has its own instance of the same class, the annotation will not be recognised. (In OSGi, each bundle has a separate class loader, and each class loader can contain its own instance of a given class.)
You can resolve this in two ways:
Import-Package
on the relevant jackson packages. The most central bundles are: jackson-annotations
, jackson-core
and jackson-databind
. In this case, use scope provided
for the jackson2 dependencies in both your bundles.compile
for jackson2 in the exporting bundle, and scope provided
in the importing bundle.Upvotes: 2