Remove duplicate keys in the json that causes by @JsonUnwrapped - RestController

Viewed 757

I have a POJO that holds another POJO:

public class Outer {

    private Long id;
    private String name;

    @JsonUnwrapped
    private Inner inner;

}

And this is the Inner class:

public class Inner {

    private Long id;
    private String name;
    private String feature;

}

As you can see both these objects may have id and name, so as whereas I used @JsonUnwrapped, there might be some duplicated keys. I have a rest controller:

@RestController
public class Temp {

    @RequestMapping("/test")
    public Outer test() {
        Inner inner = new Inner(null, "innerName", "feature");
        Outer outer = new Outer(10L, "outerName", inner);
        return outer;
    }

}

Whenever I call the method, the result would be like this: {"id":1, name:"outerName", id: null, name:"innerName","feature":"feature"}

I want to get this result:

{"id":1, name:"innerName","feature":"feature"}

I mean whenever the inner object has a value for the duplicate key, the value should be picked up from the inner object and if the value was null for the duplicate key inside the inner class, the value should be picked up from the outer object.

4 Answers

If this class structure is required for the business logic, then I'd suggest having a separate class for serialization (which is usually a good idea anyway).

public class OuterJson {

   private Long id;
   private String name;
   private String feature;

   public OuterJson(Long id, String name, String feature) {
       // assign fields
   }

   // Getters
}

// In Utillity class or as a method in Outer
public OuterJson convertToJson(Outer outer) {
    Inner inner = outer.getInner();

    return new OuterJson(
      inner == null || inner.getId() == null ? outer.getId() : inner.getId(),
      inner == null || inner.getName() == null ? outer.getName() : inner.getName(),
      inner == null ? null : inner.getFeature()
    );
}

EDIT: I'm no expert on Jackson, but I don't think this is possible with Jackson annotations alone. There are libraries such as MapStruct that can simplify operations like this. I believe it should also be able to do what you need.


An alternative could be to add getter methods that implement the logic:

public class Outer {
    @JsonIgnore
    private Long id;

    @JsonIgnore
    private String name;

    @JsonIgnore
    private Inner inner;

    @JsonProperty("id")
    public int getJsonId() {
       return inner == null || inner.getId() == null ? id : inner.getId();
    }
}

When you use @JsonUnwrapped the Inner will cover Outer same keys.

So that's not going to happen {"id":1, name:"outerName", "id": null, "name":"innerName","feature":"feature"} , {"id": null, "name":"innerName","feature":"feature"} is right

In this case,we want get {"id": 1, "name":"innerName","feature":"feature"}

the Inner need to change

  public class Inner {

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Long id;
    private String name;
    private String feature;

}

@JsonInclude(JsonInclude.Include.NON_NULL) can ignore the null value.to achieve the use of Outer id.

Try with this below pojo. i think ur problem will be solved.

public class Outer {

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Long id;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String name;
    @JsonUnwrapped
    private Inner inner;
}

public class Inner {

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Long id;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String name;
    private String feature;
}

You can do it like:

public class Outer {
    private Long id;
    private String name;

    @JsonUnwrapped
    @JsonIgnoreProperties({"id", "name"})
    private Inner inner;
}
Related