Platform 7 will contain exports of Jackson 2

Hi Developer Community :wave:,

In one of our early posts (Announcing Data Center Platform 7.0. Next step to improve our security posture) we announced that we will remove com.fasterxml.jackson.core:jackson-annotations from public exports.

We reviewed the decision and decided to make the opposite. We will provide public access to:

  • com.fasterxml.jackson.core:jackson-annotations
  • com.fasterxml.jackson.core:jackson-core
  • com.fasterxml.jackson.core:jackson-databind

Those dependencies should be used in provided scope. Please notice that “Jackson 1” (org.codehaus.jackson) won’t be available in Platform 7.

REST v2 is supporting Jackson annotations, so in most cases you can simply annotate your entities and rely on the default behaviour. If the standard marshalling from REST is not sufficient, you should rely on the JAX-RS API and register custom MessageBodyReader/MessageBodyWriter.

9 Likes

This is great; it makes our lives much easier - thanks!

3 Likes

That is great! I am using org.codehaus.jackson.map.ObjectMapper with JsonView to provide the expand logic of my REST API. Will that work too?

          String jsonPlainText = jacksonObjectMapper
    .writerWithView(expandHelper.getJsonView())
    .writeValueAsString(expandedErrorsAndPayload.payload);

Is it meant to include these REST v2 dependencies with compile scope for Confluence versions that do not depend on Platform 7, like Confluence 7.19?

Hi,

I’m not sure if that exact snippet is 100% transferable to Jackson 2 (codehaus is Jackson 1), but in general this type of code should work.

I’m not sure if I understand correctly.

We won’t be updating any older versions of products and introduce the new API there.

Embedding the code that isn’t present in the product should be safe, but we don’t support such cases. That configuration may break if used on the product version compatible with Platform 7.

2 Likes

Thank you for your clarification, @MarekTokarski!

I was looking for a solution that would reduce the workload on the side of the app that supports Confluence 7, 8, and 9. I understand that there is no quick and fast way around this compatibility issue.

1 Like

@MarekTokarski I guess the ‘Removed dependencies’ section on the main doc page for the platform upgrade is now outdated with regard to jackson-annotations, might make sense to update it, because people might have missed this CDAC post.

1 Like

The transition is unclear. Does it look like this?

  • Confluence 7.19-8.8 uses annotations from CodeHaus, such as @org.codehaus.jackson.annotate.JsonIgnoreProperties and doesn’t recognize the modern com.fasterxml annotations,
  • Confluence 8.9 recognizes both com.fasterxml and the older org.codehaus annotations,
  • Confluence 9.0 wil only recognize com.fasterxml annotations, is it correct?

So, code that is compatible with 7.19-9.2 will look like this:

// For Confluence 9.0 / Jira 10.0
@com.fasterxml.jackson.annotation.JsonIgnoreProperties(ignoreUnknown = true) 
// For Confluence 7.19 / Jira 9.4
@org.codehaus.jackson.annotate.JsonIgnoreProperties(ignoreUnknown = true)
public class MyJavaBeanDTO {

Is this understanding correct?

Hi there,

I also have a question about the @JsonIgnoreProperties annotation.

I’ve been modifying the example located at Bitbucket to test REST v2 behavior in various scenarios.
However, I’ve encountered some issues. It seems like @JsonIgnoreProperties(ignoreUnknown = true) isn’t working as expected, or perhaps I’m missing something.

Question:

Is this behavior something that requires configuration on your end?
The similar annotation from the codehaus library works as expected, out of the box.

Example:

package com.atlassian.plugins.rest.sample.v2.marshalling.mediatypes.json;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonAutoDetect
@JsonIgnoreProperties(ignoreUnknown = true)
public class JsonElementPojo {
    private String elementDescription;
    private Integer elementValue;
}
package com.atlassian.plugins.rest.sample.v2.marshalling.mediatypes.json;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonAutoDetect
@JsonIgnoreProperties(ignoreUnknown = true)
public class JsonPojo {
    private String description;
    private Integer value;
    private JsonElementPojo element;
    private List<JsonElementPojo> elements;
}
package com.atlassian.plugins.rest.sample.v2.marshalling.mediatypes;

import com.atlassian.plugins.rest.api.security.annotation.UnrestrictedAccess;
import com.atlassian.plugins.rest.sample.v2.marshalling.mediatypes.json.JsonElementPojo;
import com.atlassian.plugins.rest.sample.v2.marshalling.mediatypes.json.JsonPojo;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.Arrays;
import java.util.List;

@Path("entity")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_ATOM_XML})
public class EntityResource {

    //...

    @POST
    @Path("/json")
    @UnrestrictedAccess
    @Consumes(MediaType.APPLICATION_JSON)
    public JsonPojo postJsonTypeOnlyJsonPojo(JsonPojo jsonPojo) {
        return jsonPojo;
    }
}

Request body

{
    "description": "Set Example returned JaxbPojo",
    "value": 123,
    "element": {
        "elementDescription": "Set Element in Root",
        "elementValue": 123
    },
    "elements": [
        {
            "elementDescription": "Set Element 1",
            "elementValue": 123
        },
        {
            "elementDescription": "Set Element 2",
            "elementValue": 123
        }
    ],
    "shoudBeIgnored1": "ignored value",
    "shoudBeIgnored2": [
        "ignored value 1", "ignored value 2"
    ]
}

Response body

Unrecognized field "shoudBeIgnored1" (class com.atlassian.plugins.rest.sample.v2.marshalling.mediatypes.json.JsonPojo), not marked as ignorable (4 known properties: "value", "description", "elements", "element"])
 at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 18, column: 25] (through reference chain: com.atlassian.plugins.rest.sample.v2.marshalling.mediatypes.json.JsonPojo["shoudBeIgnored1"])

Regards,
Rafał