Miguel Guilherme
Miguel Guilherme

Reputation: 105

Jackson Unwrap / Wrap Object

I have a spring boot project and I have a class like this:

@Value
public class A {

  @JsonUnwrapped
  OrderKey key;

  String description;

  B b;
  
  @Value
  public static class B {
    String description;
  }
}

@Value
public class OrderKey {

  @JsonProperty( "_key" )
  String id;
}

I have mixins but added the Annotations in this example for brevity. This works great when serializing to JSON, the issue is when I'm trying to deserialize, probably it would work if exist some @JsonWrapped annotation.

In a nutshell, I'm trying to use ArangoDB with rest and I can create / read documents but I need to use my own Value Objects and unfortunately I can't use the key as String, it's encapsulated by an OrderKey. The @Value annotations is from lombok project.

Is there any way to achieve this?

Upvotes: 4

Views: 10296

Answers (2)

Manos Nikolaidis
Manos Nikolaidis

Reputation: 22254

You can try defining a constructor in class A annotated with @JsonCreator. Jackson is then able to use this constructor to create an A object and map the fields you expect in the JSON documents to the fields of A. Simplified example:

@Value
public class A {

    @JsonUnwrapped
    OrderKey key;

    String description;

    @JsonCreator
    public A(@JsonProperty("key") String key,
             @JsonProperty("description") String description) {
        this.key = new OrderKey(key);
        this.description = description;
    }
}

Note that this constructor for A will prevent the creation of an @AllArgsConstructor constructor implied by @Value.

It is also possible to avoid constructor annotations with Java 8 and some extra modules. Check this other answer of mine for example.

Upvotes: 2

Miguel Guilherme
Miguel Guilherme

Reputation: 105

I end up doing the serialize / deserialize inside the mixin itself, with this I can avoid the @JsonUnwrapped annotation and another mixin for the Key.

Mixin:

public class OrderMixin {

    @JsonDeserialize( using = OrderKeyDeserializer.class )
    @JsonSerialize( using = OrderKeySerializer.class )
    @JsonProperty( "_key" )
    OrderKey key;

    @JsonProperty( "description" )
    String description;

    @JsonProperty( "amount" )
    String amount;

    @JsonProperty( "operation" )
    Order.Operation operation;

    @JsonProperty( "creationDate" )
    LocalDateTime creationDate;

    public static class OrderKeySerializer extends JsonSerializer<OrderKey> {

        public OrderKeySerializer() {
            super( OrderKey.class );
        }

        @Override
        public void serialize( OrderKey value, JsonGenerator gen, SerializerProvider provider ) throws IOException {
            gen.writeString( value.getOrderId() );
        }
    }

    public static class OrderKeyDeserializer extends JsonDeserializer<OrderKey> {

        public OrderKeyDeserializer() {
            super( OrderKey.class );
        }

        @Override
        public OrderKey deserialize( JsonParser jsonParser, DeserializationContext context ) throws IOException {
            JsonNode node = jsonParser.getCodec().readTree( jsonParser );

            return OrderKey.get( node.asText() );
        }
    }

}

Value Objects:

@Value
public class Order implements Serializable {

  private static final long serialVersionUID = 901109456762331944L;

  OrderKey key;

  String description;

  String amount;

  Operation operation;

  LocalDateTime creationDate;

  @Value
  public static class Operation {

    String id;

    String description;

    String status;

    LocalDateTime creationDate;
  }

}


@Value
public class OrderKey implements Serializable {

  private static final long serialVersionUID = -8102116676316181864L;

  private String orderId;

  public static OrderKey get( String orderId ) {
      return new OrderKey( orderId );
  }

}

Upvotes: 2

Related Questions