Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson Serialization: Unwrap collection elements using

Tags:

Is there a way to serialize collection and its elements unwrapped?

For example I want to serialize unwrapped all components:

class Model {

  @JsonProperty
  @JsonUnwrapped
  Collection<Object> components;

  Model(Collection<Object> components) {
    this.components = components;
  }

  static class Component1 {
    @JsonProperty
    String stringValue;

    Component1(String stringValue) {
      this.stringValue= stringValue;
    }
  }

  static class Component2 {
    @JsonProperty
    int intValue;

    Component2(int intValue) {
      this.intValue= intValue;
    }
  }

  public static void main(String[] args) throws JsonProcessingException {
    Model model = new Model(Arrays.asList(new Component1("something"), new Component2(42)));
    String json = new ObjectMapper().writeValueAsString(model);
    System.out.println(json);
  }
}

Expected:

{"stringValue":"something","intValue":42}

But actual result is:

{"components":[{"stringValue":"something"},{"intValue":42}]}

like image 846
Nolequen Avatar asked Aug 28 '19 13:08

Nolequen


2 Answers

Custom serializer might help:

  class ModelSerializer extends JsonSerializer<Model> {

    @Override
    public void serialize(Model model, JsonGenerator generator, SerializerProvider serializers) throws IOException {
      generator.writeStartObject();

      JsonSerializer<Object> componentSerializer = serializers.findValueSerializer(getClass());
      JsonSerializer<Object> unwrappingSerializer = componentSerializer.unwrappingSerializer(NameTransformer.NOP);
      unwrappingSerializer.serialize(this, generator, serializers);

      generator.writeEndObject();
    }
  }
like image 199
Nolequen Avatar answered Sep 19 '22 09:09

Nolequen


I can't see a way to do that without custom serialization. I recommend these 2 serializers:

class ValueSerializer extends JsonSerializer<Object> {
    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider sers) throws IOException {
        for (Field field : value.getClass().getDeclaredFields()) {
            try {
                field.setAccessible(true);
                gen.writeObjectField(field.getName(), field.get(value));
            } catch (IllegalAccessException ignored) {
            }
        }
    }
}

class ModelSerializer extends JsonSerializer<Model> {
    @Override
    public void serialize(Model model, JsonGenerator gen, SerializerProvider sers) throws IOException {
        gen.writeStartObject();
        for (Object obj : model.getComponents()) {
            gen.writeObject(obj);
        }
        gen.writeEndObject();
    }
}

Notice how we don't call writeStartObject() at ValueSerializer so no extra curly braces from here, neither from writeObjectField. On the other hand in ModelSerializer writheStartObject adds curly braces, and then we dump within them each object in components

You'd also need to annotate serializable classes to use these serializers e.g.

@JsonSerialize(using = ValueSerializer.class)
class Component1 {

@JsonSerialize(using = ValueSerializer.class)
class Component2 {

@JsonSerialize(using = ModelSerializer.class)
class Model {
like image 25
Manos Nikolaidis Avatar answered Sep 22 '22 09:09

Manos Nikolaidis