Home > Net >  Java Json map object child as id
Java Json map object child as id

Time:10-14

I am creating JSON mapper that will create JSON schema for my JPA database classes. I am using mbknor-jackson-jsonSchema that works great, but I need to serialize my subclasses as id only. so far my structure is:

public class ModelPojo{
    private List<Table> table;
    private List<Table2> table2;
}

both table classes are smth like this:

@Table(name = "TABLE")
public class Table extends BaseEntity {
    @Column(name = "SMTH")
    private String smth;

    @JoinColumn(name = "TABLE2")
    private Table2 table2;   //now this is where is the problem

}

Base entity contains id

the question is, is there a way to write custom std serializer that serialize table entity to have property id_table2: "integer" not the whole object?

I tried to override serialize method for StdSerializer<BaseEntity> which does not work, it is not called when creating the schema

Edit: I now get

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "Model Pojo",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "Table": {
      "type": "array",
      "items": {
        "$ref": "#/definitions/Table"
      }
    }
    "Table2": {
      "type": "array",
      "items": {
        "$ref": "#/definitions/Table2"
      }
    }
  },
  "definitions": {
    "Table": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "id": {
          "type": "integer"
        },
        "table2": {
          "$ref": "#/definitions/Table2"
        },
        "smth": {
          "type": "string"
        }
      }
    },
    "Table2": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "id": {
          "type": "integer"
        },
        "foo": {
          "type": "string"
        }
      }
    }
  }
}

and i want to change

"table2": {
          "$ref": "#/definitions/Table2"
        },

to

"table2_id": {
              "type": "integer"
            },

the structure of joined tables is much more complex so I am trying to not manualy add @JsonIgnore and changing it manually, but write some type of serializer that retypes the child instances of BaseEntity to id, hope its understandable

CodePudding user response:

If you want to ignore all properties of your domain entities Table and Table2 apart from id (inherited from BaseEntity) while serializing ModelPojo but at the same to be able to reflect all the properties Table and Table2 while serializing them as standalone objects, you can introduce a method inside ModelPojo which to instruct the Jackson how to dial with this class.

public class ModelPojo {
    private List<Table> table;
    private List<Table2> table2;
    
    public List<Map<String, Integer>> getTable() {
        return extractIds(table);
    }

    public List<Map<String, Integer>> getTable2() {
        return extractIds(table2);
    }
    
    private List<Map<String, Integer>> extractIds(List<? extends BaseEntity> list) {
        return list.stream().map(t -> Map.of("id", t.getId())).toList();
    }
}

In the absence of real getters, getTable() and getTable2() would be used by Jackson. No data-binding annotations required.

But you might need normal getters, that's understandable.

In such case, the approach described above can be improved by introducing a single method returning a Map (as a replacement of getTable() and getTable2()) annotated with @JsonAnyGetter (to make Jackson aware of this method) and @JsonUnwrapped (to flatten the contents of this map).

The fields table and table2 should be annotated with @JsonIgnore.

public class ModelPojo {
    @JsonIgnore
    private List<Table> table;
    @JsonIgnore
    private List<Table2> table2;
    
    @JsonAnyGetter
    @JsonUnwrapped
    public Map<String, List<Map<String, Integer>>> getAll() {
        return Map.of(
            "table", extractIds(table),
            "table2", List.of()
        );
    }
    
    private List<Map<String, Integer>> extractIds(List<? extends BaseEntity> list) {
        return list.stream().map(t -> Map.of("id", t.getId())).toList();
    }

    // getters
}

I am trying to not manualy add @JsonIgnore and changing it manually, but write some type of serializer that retypes the child instances of BaseEntity to id

Sure, you can implement a custom serializer for these fields as well.

For that, you need extend JsonSerializer class and implement its abstract method serialize().

public class TableSerializer extends JsonSerializer<List<? extends BaseEntity>> {

    @Override
    public void serialize(List<? extends BaseEntity> list,
                          JsonGenerator gen,
                          SerializerProvider serializers)
                          throws IOException {
        
        gen.writeObject(extractIds(list));
    }

    private List<Map<String, Integer>> extractIds(List<? extends BaseEntity> list) {
        return list.stream().map(t -> Map.of("id", t.getId())).toList();
    }
}

public class ModelPojo {
    @JsonSerialize(using = TableSerializer.class)
    private List<Table> table;
    @JsonSerialize(using = TableSerializer.class)
    private List<Table2> table2;

    // getters
}

CodePudding user response:

In table2 you can write @JsonIgnore on the top field which you do not want to serialize it will not send it in json response. You can do it for all other fields than id

  • Related